feat(apis): ajout champs de documentation enrichie sur les API entries
- Nouveaux champs : functionalDoc, technicalDoc, externalDocUrl, contactFunctional, contactTechnical, accessRights - Entity, DTOs, service et seeder mis à jour côté backend - Page upload et api-detail mis à jour côté frontend 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:
@@ -33,6 +33,24 @@ export class ApiEntryEntity {
|
|||||||
@Column({ nullable: true, type: 'varchar', length: 36, name: 'category_id' })
|
@Column({ nullable: true, type: 'varchar', length: 36, name: 'category_id' })
|
||||||
categoryId!: string | null;
|
categoryId!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'text', name: 'functional_doc' })
|
||||||
|
functionalDoc!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'text', name: 'technical_doc' })
|
||||||
|
technicalDoc!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'varchar', length: 500, name: 'external_doc_url' })
|
||||||
|
externalDocUrl!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'varchar', length: 255, name: 'contact_functional' })
|
||||||
|
contactFunctional!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'varchar', length: 255, name: 'contact_technical' })
|
||||||
|
contactTechnical!: string | null;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'text', name: 'access_rights' })
|
||||||
|
accessRights!: string | null;
|
||||||
|
|
||||||
@CreateDateColumn({ name: 'created_at' })
|
@CreateDateColumn({ name: 'created_at' })
|
||||||
createdAt!: Date;
|
createdAt!: Date;
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ export class ApisService {
|
|||||||
yamlContent: dto.yamlContent,
|
yamlContent: dto.yamlContent,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: dto.categoryId ?? null,
|
categoryId: dto.categoryId ?? null,
|
||||||
|
functionalDoc: dto.functionalDoc ?? null,
|
||||||
|
technicalDoc: dto.technicalDoc ?? null,
|
||||||
|
externalDocUrl: dto.externalDocUrl ?? null,
|
||||||
|
contactFunctional: dto.contactFunctional ?? null,
|
||||||
|
contactTechnical: dto.contactTechnical ?? null,
|
||||||
|
accessRights: dto.accessRights ?? null,
|
||||||
});
|
});
|
||||||
const saved = await this.repo.save(entity);
|
const saved = await this.repo.save(entity);
|
||||||
return toApiEntry(saved);
|
return toApiEntry(saved);
|
||||||
@@ -115,6 +121,12 @@ function toApiEntry(entity: ApiEntryEntity): ApiEntry {
|
|||||||
status: entity.status,
|
status: entity.status,
|
||||||
errorMessage: entity.errorMessage,
|
errorMessage: entity.errorMessage,
|
||||||
categoryId: entity.categoryId,
|
categoryId: entity.categoryId,
|
||||||
|
functionalDoc: entity.functionalDoc,
|
||||||
|
technicalDoc: entity.technicalDoc,
|
||||||
|
externalDocUrl: entity.externalDocUrl,
|
||||||
|
contactFunctional: entity.contactFunctional,
|
||||||
|
contactTechnical: entity.contactTechnical,
|
||||||
|
accessRights: entity.accessRights,
|
||||||
createdAt: entity.createdAt.toISOString(),
|
createdAt: entity.createdAt.toISOString(),
|
||||||
updatedAt: entity.updatedAt.toISOString(),
|
updatedAt: entity.updatedAt.toISOString(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,4 +24,28 @@ export class CreateApiEntryDto {
|
|||||||
@IsUUID()
|
@IsUUID()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
categoryId?: string;
|
categoryId?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
functionalDoc?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
technicalDoc?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
externalDocUrl?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
contactFunctional?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
contactTechnical?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
accessRights?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,28 @@ export class UpdateApiEntryDto {
|
|||||||
@IsUUID()
|
@IsUUID()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
categoryId?: string | null;
|
categoryId?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
functionalDoc?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
technicalDoc?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
externalDocUrl?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
contactFunctional?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
contactTechnical?: string | null;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
accessRights?: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
|
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import * as fs from 'fs/promises';
|
||||||
import { ApiEntryEntity } from '../apis/api-entry.entity';
|
import { ApiEntryEntity } from '../apis/api-entry.entity';
|
||||||
import { CategoryEntity } from '../categories/category.entity';
|
import { CategoryEntity } from '../categories/category.entity';
|
||||||
import { DocsGenerationService } from '../docs-generation/docs-generation.service';
|
import { DocsGenerationService } from '../docs-generation/docs-generation.service';
|
||||||
@@ -595,11 +596,26 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async onApplicationBootstrap(): Promise<void> {
|
async onApplicationBootstrap(): Promise<void> {
|
||||||
|
const forceReseed = process.env.FORCE_RESEED === 'true';
|
||||||
|
if (forceReseed) {
|
||||||
|
await this.reset();
|
||||||
|
}
|
||||||
const count = await this.apiRepo.count();
|
const count = await this.apiRepo.count();
|
||||||
if (count > 0) return; /* Idempotent — ne ré-exécute pas si des données existent */
|
if (count > 0) return; /* Idempotent — ne ré-exécute pas si des données existent */
|
||||||
await this.seed();
|
await this.seed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async reset(): Promise<void> {
|
||||||
|
/* Supprimer toutes les entrées puis les catégories */
|
||||||
|
await this.apiRepo.delete({});
|
||||||
|
await this.categoryRepo.delete({});
|
||||||
|
/* Nettoyer le répertoire docs-output */
|
||||||
|
const docsDir = process.env.DOCS_OUTPUT_DIR ?? '/app/docs-output';
|
||||||
|
await fs.rm(docsDir, { recursive: true, force: true });
|
||||||
|
await fs.mkdir(docsDir, { recursive: true });
|
||||||
|
console.log('[Seeder] Reset complet — données supprimées, docs nettoyées.');
|
||||||
|
}
|
||||||
|
|
||||||
private async seed(): Promise<void> {
|
private async seed(): Promise<void> {
|
||||||
/* Catégories racines */
|
/* Catégories racines */
|
||||||
const ecommerce = await this.categoryRepo.save(
|
const ecommerce = await this.categoryRepo.save(
|
||||||
@@ -680,6 +696,12 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
yamlContent: PETSTORE_YAML,
|
yamlContent: PETSTORE_YAML,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: produits.id,
|
categoryId: produits.id,
|
||||||
|
functionalDoc: 'Cas d\'usage : gestion du catalogue produits. Permet de lister, créer et consulter des animaux de compagnie. Usage typique : intégration e-commerce, démo API REST.',
|
||||||
|
technicalDoc: 'Authentification Bearer token requise. Pagination via paramètre `limit` (max 100). Réponses JSON selon schéma OpenAPI 3.0. Endpoint base : https://petstore.swagger.io/v3.',
|
||||||
|
externalDocUrl: null,
|
||||||
|
contactFunctional: 'Équipe Produit',
|
||||||
|
contactTechnical: 'Équipe API',
|
||||||
|
accessRights: 'API publique — aucune habilitation requise.',
|
||||||
}),
|
}),
|
||||||
this.apiRepo.create({
|
this.apiRepo.create({
|
||||||
title: 'Streetlights Kafka API',
|
title: 'Streetlights Kafka API',
|
||||||
@@ -690,6 +712,12 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
yamlContent: STREETLIGHTS_YAML,
|
yamlContent: STREETLIGHTS_YAML,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: evenements.id,
|
categoryId: evenements.id,
|
||||||
|
functionalDoc: 'Gestion de l\'éclairage urbain IoT. Permet de recevoir les mesures de luminosité des lampadaires et d\'envoyer des commandes d\'allumage/extinction à distance.',
|
||||||
|
technicalDoc: 'Broker Kafka sécurisé avec SCRAM-SHA-512. Topics : smartylighting.streetlights.1.0.*. Schémas de messages définis en AsyncAPI 3.0. Adresse broker : test.mykafkacluster.org:18092.',
|
||||||
|
externalDocUrl: null,
|
||||||
|
contactFunctional: 'Bureau Infrastructure',
|
||||||
|
contactTechnical: 'ops@example.com',
|
||||||
|
accessRights: 'Accès sur demande — habilitation DSI requise.',
|
||||||
}),
|
}),
|
||||||
this.apiRepo.create({
|
this.apiRepo.create({
|
||||||
title: 'Account Service',
|
title: 'Account Service',
|
||||||
@@ -699,6 +727,12 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
yamlContent: ACCOUNT_SERVICE_YAML,
|
yamlContent: ACCOUNT_SERVICE_YAML,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: notifications.id,
|
categoryId: notifications.id,
|
||||||
|
functionalDoc: 'Cycle de vie du compte utilisateur. Publie des événements lors de l\'inscription et du changement de mot de passe. Utilisé par les services de notification et d\'audit.',
|
||||||
|
technicalDoc: 'Consommer via broker AMQP ou Kafka. Canaux : user/signedup, user/passwordchanged. Payloads JSON avec horodatage ISO 8601. Spec AsyncAPI 3.0.',
|
||||||
|
externalDocUrl: null,
|
||||||
|
contactFunctional: 'Équipe Comptes',
|
||||||
|
contactTechnical: 'dev-core@example.com',
|
||||||
|
accessRights: 'Interne uniquement — accès réservé aux services du SI.',
|
||||||
}),
|
}),
|
||||||
this.apiRepo.create({
|
this.apiRepo.create({
|
||||||
title: 'Orders API',
|
title: 'Orders API',
|
||||||
@@ -708,6 +742,12 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
yamlContent: ORDERS_YAML,
|
yamlContent: ORDERS_YAML,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: commandes.id,
|
categoryId: commandes.id,
|
||||||
|
functionalDoc: 'Gestion des commandes clients : création, consultation, mise à jour du statut. Supporte les webhooks pour les transitions de statut (confirmed, shipped, delivered, cancelled).',
|
||||||
|
technicalDoc: 'REST + JWT Bearer. Pagination via paramètres `page` et `limit`. Webhook de statut : POST vers URL configurée lors de la transition. Base URL : https://api.example.com/v1.',
|
||||||
|
externalDocUrl: null,
|
||||||
|
contactFunctional: 'Équipe Commerce',
|
||||||
|
contactTechnical: 'api-orders@example.com',
|
||||||
|
accessRights: 'Partenaires agréés uniquement — convention de partenariat requise.',
|
||||||
}),
|
}),
|
||||||
this.apiRepo.create({
|
this.apiRepo.create({
|
||||||
title: 'Auth API',
|
title: 'Auth API',
|
||||||
@@ -717,6 +757,12 @@ export class SeederService implements OnApplicationBootstrap {
|
|||||||
yamlContent: AUTH_YAML,
|
yamlContent: AUTH_YAML,
|
||||||
status: 'PENDING',
|
status: 'PENDING',
|
||||||
categoryId: auth.id,
|
categoryId: auth.id,
|
||||||
|
functionalDoc: 'SSO centralisé avec tokens JWT. Gère la connexion, le rafraîchissement de token et la déconnexion. Exposé à tous les services du SI comme fournisseur d\'identité.',
|
||||||
|
technicalDoc: 'Bearer JWT (RS256). Endpoint principal : POST /auth/login. Refresh via POST /auth/refresh. Durée access token : 15 min. Durée refresh token : 7 jours. Base URL : https://auth.example.com/v1.',
|
||||||
|
externalDocUrl: null,
|
||||||
|
contactFunctional: 'Équipe Sécurité',
|
||||||
|
contactTechnical: 'securite@example.com',
|
||||||
|
accessRights: 'Restreint — habilitation RSSI requise avant intégration.',
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ export class UploadsController {
|
|||||||
description?: string;
|
description?: string;
|
||||||
type?: ApiType;
|
type?: ApiType;
|
||||||
categoryId?: string;
|
categoryId?: string;
|
||||||
|
functionalDoc?: string;
|
||||||
|
technicalDoc?: string;
|
||||||
|
externalDocUrl?: string;
|
||||||
|
contactFunctional?: string;
|
||||||
|
contactTechnical?: string;
|
||||||
|
accessRights?: string;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
if (!files || files.length === 0) throw new BadRequestException('YAML file is required');
|
if (!files || files.length === 0) throw new BadRequestException('YAML file is required');
|
||||||
@@ -86,6 +92,12 @@ export class UploadsController {
|
|||||||
type: apiType,
|
type: apiType,
|
||||||
yamlContent,
|
yamlContent,
|
||||||
categoryId: body.categoryId || undefined,
|
categoryId: body.categoryId || undefined,
|
||||||
|
functionalDoc: body.functionalDoc || undefined,
|
||||||
|
technicalDoc: body.technicalDoc || undefined,
|
||||||
|
externalDocUrl: body.externalDocUrl || undefined,
|
||||||
|
contactFunctional: body.contactFunctional || undefined,
|
||||||
|
contactTechnical: body.contactTechnical || undefined,
|
||||||
|
accessRights: body.accessRights || undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Fire-and-forget : génération asynchrone */
|
/* Fire-and-forget : génération asynchrone */
|
||||||
|
|||||||
@@ -111,6 +111,81 @@ import { ApiEntry } from '@datacat/shared';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Documentation fonctionnelle -->
|
||||||
|
@if (entry.functionalDoc) {
|
||||||
|
<div class="fr-card fr-mb-4w">
|
||||||
|
<div class="fr-card__body">
|
||||||
|
<div class="fr-card__content">
|
||||||
|
<h2 class="fr-h5 fr-mb-2w">Documentation fonctionnelle</h2>
|
||||||
|
<p style="white-space: pre-wrap">{{ entry.functionalDoc }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Documentation technique -->
|
||||||
|
@if (entry.technicalDoc) {
|
||||||
|
<div class="fr-card fr-mb-4w">
|
||||||
|
<div class="fr-card__body">
|
||||||
|
<div class="fr-card__content">
|
||||||
|
<h2 class="fr-h5 fr-mb-2w">Documentation technique</h2>
|
||||||
|
<p style="white-space: pre-wrap">{{ entry.technicalDoc }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Contacts -->
|
||||||
|
@if (entry.contactFunctional || entry.contactTechnical) {
|
||||||
|
<div class="fr-card fr-mb-4w">
|
||||||
|
<div class="fr-card__body">
|
||||||
|
<div class="fr-card__content">
|
||||||
|
<h2 class="fr-h5 fr-mb-2w">Contacts</h2>
|
||||||
|
<dl class="fr-grid-row fr-grid-row--gutters">
|
||||||
|
@if (entry.contactFunctional) {
|
||||||
|
<div class="fr-col-12 fr-col-md-6">
|
||||||
|
<dt class="fr-text--bold">Contact fonctionnel</dt>
|
||||||
|
<dd>{{ entry.contactFunctional }}</dd>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (entry.contactTechnical) {
|
||||||
|
<div class="fr-col-12 fr-col-md-6">
|
||||||
|
<dt class="fr-text--bold">Contact technique</dt>
|
||||||
|
<dd>{{ entry.contactTechnical }}</dd>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Droits d'accès -->
|
||||||
|
@if (entry.accessRights) {
|
||||||
|
<div class="fr-card fr-mb-4w">
|
||||||
|
<div class="fr-card__body">
|
||||||
|
<div class="fr-card__content">
|
||||||
|
<h2 class="fr-h5 fr-mb-2w">Droits d'accès</h2>
|
||||||
|
<p style="white-space: pre-wrap">{{ entry.accessRights }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Documentation externe -->
|
||||||
|
@if (entry.externalDocUrl) {
|
||||||
|
<div class="fr-mb-4w">
|
||||||
|
<a
|
||||||
|
[href]="entry.externalDocUrl"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="fr-btn fr-btn--secondary fr-icon-external-link-line fr-btn--icon-left"
|
||||||
|
>
|
||||||
|
Documentation externe
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div class="fr-btns-group fr-btns-group--inline-sm">
|
<div class="fr-btns-group fr-btns-group--inline-sm">
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ import { Category } from '@datacat/shared';
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fr-input-group fr-mb-4w">
|
<div class="fr-input-group fr-mb-3w">
|
||||||
<label class="fr-label" for="description-input">
|
<label class="fr-label" for="description-input">
|
||||||
Description <span class="fr-hint-text">Optionnel</span>
|
Description <span class="fr-hint-text">Optionnel</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -171,6 +171,84 @@ import { Category } from '@datacat/shared';
|
|||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-3w">
|
||||||
|
<label class="fr-label" for="functional-doc-input">
|
||||||
|
Documentation fonctionnelle <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="functional-doc-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="functionalDoc"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Cas d'usage, contexte métier..."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-3w">
|
||||||
|
<label class="fr-label" for="technical-doc-input">
|
||||||
|
Documentation technique <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="technical-doc-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="technicalDoc"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Guide d'intégration technique..."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-3w">
|
||||||
|
<label class="fr-label" for="external-doc-url-input">
|
||||||
|
URL documentation externe <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="external-doc-url-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="externalDocUrl"
|
||||||
|
type="text"
|
||||||
|
placeholder="https://..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-3w">
|
||||||
|
<label class="fr-label" for="contact-functional-input">
|
||||||
|
Contact fonctionnel <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-functional-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="contactFunctional"
|
||||||
|
type="text"
|
||||||
|
placeholder="Nom, email, téléphone..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-3w">
|
||||||
|
<label class="fr-label" for="contact-technical-input">
|
||||||
|
Contact technique <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="contact-technical-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="contactTechnical"
|
||||||
|
type="text"
|
||||||
|
placeholder="Nom, email, téléphone..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fr-input-group fr-mb-4w">
|
||||||
|
<label class="fr-label" for="access-rights-input">
|
||||||
|
Droits d'accès <span class="fr-hint-text">Optionnel</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="access-rights-input"
|
||||||
|
class="fr-input"
|
||||||
|
formControlName="accessRights"
|
||||||
|
rows="3"
|
||||||
|
placeholder="Processus d'habilitation, conditions d'accès..."
|
||||||
|
></textarea>
|
||||||
|
</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" [disabled]="metaForm.invalid">Suivant</button>
|
<button type="submit" class="fr-btn" [disabled]="metaForm.invalid">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)">
|
||||||
@@ -283,6 +361,12 @@ export class UploadComponent implements OnInit {
|
|||||||
type: ['ASYNCAPI', Validators.required],
|
type: ['ASYNCAPI', Validators.required],
|
||||||
categoryId: [''],
|
categoryId: [''],
|
||||||
description: [''],
|
description: [''],
|
||||||
|
functionalDoc: [''],
|
||||||
|
technicalDoc: [''],
|
||||||
|
externalDocUrl: [''],
|
||||||
|
contactFunctional: [''],
|
||||||
|
contactTechnical: [''],
|
||||||
|
accessRights: [''],
|
||||||
});
|
});
|
||||||
|
|
||||||
titleInvalid = computed(
|
titleInvalid = computed(
|
||||||
@@ -374,6 +458,24 @@ export class UploadComponent implements OnInit {
|
|||||||
if (this.metaForm.value.description) {
|
if (this.metaForm.value.description) {
|
||||||
formData.append('description', this.metaForm.value.description);
|
formData.append('description', this.metaForm.value.description);
|
||||||
}
|
}
|
||||||
|
if (this.metaForm.value.functionalDoc) {
|
||||||
|
formData.append('functionalDoc', this.metaForm.value.functionalDoc);
|
||||||
|
}
|
||||||
|
if (this.metaForm.value.technicalDoc) {
|
||||||
|
formData.append('technicalDoc', this.metaForm.value.technicalDoc);
|
||||||
|
}
|
||||||
|
if (this.metaForm.value.externalDocUrl) {
|
||||||
|
formData.append('externalDocUrl', this.metaForm.value.externalDocUrl);
|
||||||
|
}
|
||||||
|
if (this.metaForm.value.contactFunctional) {
|
||||||
|
formData.append('contactFunctional', this.metaForm.value.contactFunctional);
|
||||||
|
}
|
||||||
|
if (this.metaForm.value.contactTechnical) {
|
||||||
|
formData.append('contactTechnical', this.metaForm.value.contactTechnical);
|
||||||
|
}
|
||||||
|
if (this.metaForm.value.accessRights) {
|
||||||
|
formData.append('accessRights', this.metaForm.value.accessRights);
|
||||||
|
}
|
||||||
|
|
||||||
this.apiService.upload(formData).subscribe({
|
this.apiService.upload(formData).subscribe({
|
||||||
next: (entry) => {
|
next: (entry) => {
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ export interface ApiEntry {
|
|||||||
status: ApiStatus;
|
status: ApiStatus;
|
||||||
errorMessage: string | null;
|
errorMessage: string | null;
|
||||||
categoryId: string | null;
|
categoryId: string | null;
|
||||||
|
functionalDoc: string | null;
|
||||||
|
technicalDoc: string | null;
|
||||||
|
externalDocUrl: string | null;
|
||||||
|
contactFunctional: string | null;
|
||||||
|
contactTechnical: string | null;
|
||||||
|
accessRights: string | null;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user