From d2d140640e731547658a4f806d24c7a1b9bcc097 Mon Sep 17 00:00:00 2001 From: z3n Date: Sun, 28 Jun 2026 21:19:21 +0000 Subject: [PATCH] front: extrait les templates inline vers des fichiers .html MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit upload (900->427 l.) et api-detail (700->330 l.) : le template inline géant passe en templateUrl. Aucun changement de comportement (build + eslint a11y + runtime OK). Composants bien plus navigables ; les .html sont désormais lintés par angular-eslint (a11y). Co-Authored-By: Claude Opus 4.8 --- .../api-detail/api-detail.component.html | 369 ++++++++++++++ .../pages/api-detail/api-detail.component.ts | 372 +------------- .../app/pages/upload/upload.component.html | 472 +++++++++++++++++ .../src/app/pages/upload/upload.component.ts | 475 +----------------- 4 files changed, 843 insertions(+), 845 deletions(-) create mode 100644 front-public/src/app/pages/api-detail/api-detail.component.html create mode 100644 front-public/src/app/pages/upload/upload.component.html diff --git a/front-public/src/app/pages/api-detail/api-detail.component.html b/front-public/src/app/pages/api-detail/api-detail.component.html new file mode 100644 index 0000000..1e1a89f --- /dev/null +++ b/front-public/src/app/pages/api-detail/api-detail.component.html @@ -0,0 +1,369 @@ +
+ + + @if (loading()) { +
+

Chargement...

+
+ } + + @if (error()) { +
+

Erreur

+

{{ error() }}

+
+ } + + @if (api(); as entry) { + + Retour + + +
+ +
+

{{ entry.title }}

+ @if (versions().length <= 1) { + v{{ entry.version }} + } @else { + + } +
+ +
+ + Voir la documentation + +
+ + @if (actionsOpen()) { +
+ + + Télécharger YAML + + @if (entry.status !== 'GENERATED') { + + } + +
+ } +
+
+
+ + +
+ + +
+ + + @if (activeTab() === 'info') { + @if (!editingInfo()) { +
+
+
+
+
+
Version
+
+ {{ entry.version }} + @if (!entry.isCurrent) { + + } +
+
+
+
Type
+
{{ entry.type }}
+
+
+
Statut
+
+ {{ statusLabel(entry.status) }} + @if (entry.status === 'ERROR' && entry.errorMessage) { +

{{ entry.errorMessage }}

+ } +
+
+
+
Fournisseur
+
{{ entry.provider }}
+
+ @if (entry.description) { +
+
Description
+
{{ entry.description }}
+
+ } +
+
Créé le
+
{{ entry.createdAt | date:'dd/MM/yyyy HH:mm' }}
+
+
+
Mis à jour le
+
{{ entry.updatedAt | date:'dd/MM/yyyy HH:mm' }}
+
+
+
+ +
+
+
+
+ } + + @if (editingInfo()) { +
+ +

Titre *

+
+
+
+ + +
+
+
+
+ + + @if (infoForm.get('name')?.invalid && infoForm.get('name')?.touched) { +

Le nom est obligatoire.

+ } +
+
+
+ + +
+ + + @if (infoForm.get('provider')?.invalid && infoForm.get('provider')?.touched) { +

Le fournisseur est obligatoire.

+ } +
+ + +

Version *

+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ + +
+ + +
+ + +
+ + +
+ +
+ + +
+
+ } + } + + + @if (activeTab() === 'contacts') { + @if (!editingContacts()) { +
+
+
+
+
+

Contact métier

+

{{ entry.contactFunctionalName }}

+

{{ entry.contactFunctionalEntity }}

+

{{ entry.contactFunctionalEmail }}

+
+
+

Contact technique

+

{{ entry.contactTechnicalName }}

+

{{ entry.contactTechnicalEntity }}

+

{{ entry.contactTechnicalEmail }}

+
+
+
+ +
+
+
+
+ } + + @if (editingContacts()) { +
+ +

Contact métier *

+
+
+
+ + + @if (contactForm.get('contactFunctionalName')?.invalid && contactForm.get('contactFunctionalName')?.touched) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (contactForm.get('contactFunctionalEntity')?.invalid && contactForm.get('contactFunctionalEntity')?.touched) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (contactForm.get('contactFunctionalEmail')?.invalid && contactForm.get('contactFunctionalEmail')?.touched) { +

Email valide requis.

+ } +
+
+
+ + +

Contact technique *

+
+
+
+ + + @if (contactForm.get('contactTechnicalName')?.invalid && contactForm.get('contactTechnicalName')?.touched) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (contactForm.get('contactTechnicalEntity')?.invalid && contactForm.get('contactTechnicalEntity')?.touched) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (contactForm.get('contactTechnicalEmail')?.invalid && contactForm.get('contactTechnicalEmail')?.touched) { +

Email valide requis.

+ } +
+
+
+ +
+ + +
+
+ } + } + + } +
diff --git a/front-public/src/app/pages/api-detail/api-detail.component.ts b/front-public/src/app/pages/api-detail/api-detail.component.ts index d0bd0c0..fffd128 100644 --- a/front-public/src/app/pages/api-detail/api-detail.component.ts +++ b/front-public/src/app/pages/api-detail/api-detail.component.ts @@ -22,377 +22,7 @@ import { ApiEntry, ApiEntryListItem, Category } from '@datacat/shared'; standalone: true, imports: [CommonModule, RouterLink, ReactiveFormsModule, BreadcrumbComponent], changeDetection: ChangeDetectionStrategy.OnPush, - template: ` -
- - - @if (loading()) { -
-

Chargement...

-
- } - - @if (error()) { -
-

Erreur

-

{{ error() }}

-
- } - - @if (api(); as entry) { - - Retour - - -
- -
-

{{ entry.title }}

- @if (versions().length <= 1) { - v{{ entry.version }} - } @else { - - } -
- -
- - Voir la documentation - -
- - @if (actionsOpen()) { -
- - - Télécharger YAML - - @if (entry.status !== 'GENERATED') { - - } - -
- } -
-
-
- - -
- - -
- - - @if (activeTab() === 'info') { - @if (!editingInfo()) { -
-
-
-
-
-
Version
-
- {{ entry.version }} - @if (!entry.isCurrent) { - - } -
-
-
-
Type
-
{{ entry.type }}
-
-
-
Statut
-
- {{ statusLabel(entry.status) }} - @if (entry.status === 'ERROR' && entry.errorMessage) { -

{{ entry.errorMessage }}

- } -
-
-
-
Fournisseur
-
{{ entry.provider }}
-
- @if (entry.description) { -
-
Description
-
{{ entry.description }}
-
- } -
-
Créé le
-
{{ entry.createdAt | date:'dd/MM/yyyy HH:mm' }}
-
-
-
Mis à jour le
-
{{ entry.updatedAt | date:'dd/MM/yyyy HH:mm' }}
-
-
-
- -
-
-
-
- } - - @if (editingInfo()) { -
- -

Titre *

-
-
-
- - -
-
-
-
- - - @if (infoForm.get('name')?.invalid && infoForm.get('name')?.touched) { -

Le nom est obligatoire.

- } -
-
-
- - -
- - - @if (infoForm.get('provider')?.invalid && infoForm.get('provider')?.touched) { -

Le fournisseur est obligatoire.

- } -
- - -

Version *

-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- - -
- - -
- - -
- - -
- -
- - -
-
- } - } - - - @if (activeTab() === 'contacts') { - @if (!editingContacts()) { -
-
-
-
-
-

Contact métier

-

{{ entry.contactFunctionalName }}

-

{{ entry.contactFunctionalEntity }}

-

{{ entry.contactFunctionalEmail }}

-
-
-

Contact technique

-

{{ entry.contactTechnicalName }}

-

{{ entry.contactTechnicalEntity }}

-

{{ entry.contactTechnicalEmail }}

-
-
-
- -
-
-
-
- } - - @if (editingContacts()) { -
- -

Contact métier *

-
-
-
- - - @if (contactForm.get('contactFunctionalName')?.invalid && contactForm.get('contactFunctionalName')?.touched) { -

Obligatoire.

- } -
-
-
-
- - - @if (contactForm.get('contactFunctionalEntity')?.invalid && contactForm.get('contactFunctionalEntity')?.touched) { -

Obligatoire.

- } -
-
-
-
- - - @if (contactForm.get('contactFunctionalEmail')?.invalid && contactForm.get('contactFunctionalEmail')?.touched) { -

Email valide requis.

- } -
-
-
- - -

Contact technique *

-
-
-
- - - @if (contactForm.get('contactTechnicalName')?.invalid && contactForm.get('contactTechnicalName')?.touched) { -

Obligatoire.

- } -
-
-
-
- - - @if (contactForm.get('contactTechnicalEntity')?.invalid && contactForm.get('contactTechnicalEntity')?.touched) { -

Obligatoire.

- } -
-
-
-
- - - @if (contactForm.get('contactTechnicalEmail')?.invalid && contactForm.get('contactTechnicalEmail')?.touched) { -

Email valide requis.

- } -
-
-
- -
- - -
-
- } - } - - } -
- `, + templateUrl: "./api-detail.component.html", }) export class ApiDetailComponent implements OnInit, OnDestroy { private route = inject(ActivatedRoute); diff --git a/front-public/src/app/pages/upload/upload.component.html b/front-public/src/app/pages/upload/upload.component.html new file mode 100644 index 0000000..df817ed --- /dev/null +++ b/front-public/src/app/pages/upload/upload.component.html @@ -0,0 +1,472 @@ +
+ + +

Importer une API

+ + +
+ @for (title of stepTitles; track $index) { +
+
+ @if (step() > $index + 1) { + + } @else { + {{ $index + 1 }} + } +
+ + {{ title }} + +
+ @if ($index < stepTitles.length - 1) { +
+
+ } + } +
+ + + @if (step() === 1) { +
+ + +
+ + @if (fileError()) { +
+

{{ fileError() }}

+
+ } + + @if (selectedFiles().length > 0) { +
+ @for (file of selectedFiles(); track file.name) { +
+ + {{ file.name }} + ({{ (file.size / 1024).toFixed(1) }} Ko) + + @if (file.name === detectedMainFilename()) { + Principal + } @else if (selectedFiles().length > 1) { + Secondaire + } +
+ } +
+ + @if (validating()) { +
+

Validation en cours...

+
+ } @else if (validationDone()) { + @if (validationErrors().length > 0) { +
+

Fichier(s) invalide(s)

+ @for (err of validationErrors(); track err.file) { +

{{ err.file ? err.file + ' : ' : '' }}{{ err.message }}

+ } +
+ } @else { +
+

Fichier(s) valide(s)

+

Le fichier a été validé avec succès.

+
+ } + } + } + +
+ + Annuler +
+ } + + + @if (step() === 2) { + + @if (fromApi(); as origin) { +
+

+ Nouvelle version de : {{ origin.title }} (v{{ origin.version }}) + — le nom et la convention sont verrouillés. +

+
+ } + +
+ + +

Titre *

+
+
+
+ + + @if (conventionInvalid()) { +

La convention est obligatoire.

+ } +
+
+
+
+ + + @if (nameInvalid()) { +

Le nom est obligatoire.

+ } +
+
+
+

Titre complet : {{ previewTitle() }}

+ + +
+ + +
+ + +
+ + + @if (providerInvalid()) { +

Le fournisseur est obligatoire.

+ } +
+ + +
+ + + @if (detectedType()) { +

Détecté automatiquement depuis le fichier YAML

+ } +
+ + +
+ + +
+ + +

Version *

+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ + @if (versionAlreadyExists()) { +
+

Version déjà existante

+

+ La version {{ formValues().versionMajor }}.{{ formValues().versionMinor }}.{{ formValues().versionPatch }} + existe déjà pour cette API. Choisissez un numéro de version différent. +

+
+ } + +
+ + +
+
+ } + + + @if (step() === 3) { +
+ + +

Contact métier *

+
+
+
+ + + @if (fieldInvalid('contactFunctionalName')) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (fieldInvalid('contactFunctionalEntity')) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (fieldInvalid('contactFunctionalEmail')) { +

Email valide requis.

+ } +
+
+
+ + +

Contact technique *

+
+
+
+ + + @if (fieldInvalid('contactTechnicalName')) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (fieldInvalid('contactTechnicalEntity')) { +

Obligatoire.

+ } +
+
+
+
+ + + @if (fieldInvalid('contactTechnicalEmail')) { +

Email valide requis.

+ } +
+
+
+ +
+ + +
+
+ } + + + @if (step() === 4) { +
+
+
+

Récapitulatif

+
+
+
Fichier{{ selectedFiles().length > 1 ? 's' : '' }}
+
+ @if (selectedFiles().length === 0) { + Aucun fichier + } @else if (selectedFiles().length === 1) { + {{ selectedFiles()[0].name }} + } @else { + @for (f of selectedFiles(); track f.name) { +
+ {{ f.name }} + @if (f.name === detectedMainFilename()) { + Principal + } +
+ } + } +
+
+
+
Type
+
{{ displayType() }}
+
+
+
Titre
+
{{ previewTitle() }}
+
+
+
Version
+
{{ metaForm.value.versionMajor }}.{{ metaForm.value.versionMinor }}.{{ metaForm.value.versionPatch }}
+
+
+
Fournisseur
+
{{ metaForm.value.provider }}
+
+ @if (metaForm.value.categoryId) { +
+
Catégorie
+
{{ selectedCategoryName() }}
+
+ } + @if (metaForm.value.description) { +
+
Description
+
{{ metaForm.value.description }}
+
+ } +
+
Contact métier
+
+ {{ metaForm.value.contactFunctionalName }}
+ {{ metaForm.value.contactFunctionalEntity }}
+ {{ metaForm.value.contactFunctionalEmail }} +
+
+
+
Contact technique
+
+ {{ metaForm.value.contactTechnicalName }}
+ {{ metaForm.value.contactTechnicalEntity }}
+ {{ metaForm.value.contactTechnicalEmail }} +
+
+
+
+
+
+ + @if (uploadError()) { +
+

Erreur lors de l'import

+

{{ uploadError() }}

+
+ } + +
+ + +
+ } +
diff --git a/front-public/src/app/pages/upload/upload.component.ts b/front-public/src/app/pages/upload/upload.component.ts index e1b7eb1..5f717dc 100644 --- a/front-public/src/app/pages/upload/upload.component.ts +++ b/front-public/src/app/pages/upload/upload.component.ts @@ -21,480 +21,7 @@ import { ApiEntry, ApiEntryListItem, Category, API_CONVENTION_LABELS, ApiConvent standalone: true, imports: [CommonModule, ReactiveFormsModule, RouterLink, BreadcrumbComponent], changeDetection: ChangeDetectionStrategy.OnPush, - template: ` -
- - -

Importer une API

- - -
- @for (title of stepTitles; track $index) { -
-
- @if (step() > $index + 1) { - - } @else { - {{ $index + 1 }} - } -
- - {{ title }} - -
- @if ($index < stepTitles.length - 1) { -
-
- } - } -
- - - @if (step() === 1) { -
- - -
- - @if (fileError()) { -
-

{{ fileError() }}

-
- } - - @if (selectedFiles().length > 0) { -
- @for (file of selectedFiles(); track file.name) { -
- - {{ file.name }} - ({{ (file.size / 1024).toFixed(1) }} Ko) - - @if (file.name === detectedMainFilename()) { - Principal - } @else if (selectedFiles().length > 1) { - Secondaire - } -
- } -
- - @if (validating()) { -
-

Validation en cours...

-
- } @else if (validationDone()) { - @if (validationErrors().length > 0) { -
-

Fichier(s) invalide(s)

- @for (err of validationErrors(); track err.file) { -

{{ err.file ? err.file + ' : ' : '' }}{{ err.message }}

- } -
- } @else { -
-

Fichier(s) valide(s)

-

Le fichier a été validé avec succès.

-
- } - } - } - -
- - Annuler -
- } - - - @if (step() === 2) { - - @if (fromApi(); as origin) { -
-

- Nouvelle version de : {{ origin.title }} (v{{ origin.version }}) - — le nom et la convention sont verrouillés. -

-
- } - -
- - -

Titre *

-
-
-
- - - @if (conventionInvalid()) { -

La convention est obligatoire.

- } -
-
-
-
- - - @if (nameInvalid()) { -

Le nom est obligatoire.

- } -
-
-
-

Titre complet : {{ previewTitle() }}

- - -
- - -
- - -
- - - @if (providerInvalid()) { -

Le fournisseur est obligatoire.

- } -
- - -
- - - @if (detectedType()) { -

Détecté automatiquement depuis le fichier YAML

- } -
- - -
- - -
- - -

Version *

-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
- - @if (versionAlreadyExists()) { -
-

Version déjà existante

-

- La version {{ formValues().versionMajor }}.{{ formValues().versionMinor }}.{{ formValues().versionPatch }} - existe déjà pour cette API. Choisissez un numéro de version différent. -

-
- } - -
- - -
-
- } - - - @if (step() === 3) { -
- - -

Contact métier *

-
-
-
- - - @if (fieldInvalid('contactFunctionalName')) { -

Obligatoire.

- } -
-
-
-
- - - @if (fieldInvalid('contactFunctionalEntity')) { -

Obligatoire.

- } -
-
-
-
- - - @if (fieldInvalid('contactFunctionalEmail')) { -

Email valide requis.

- } -
-
-
- - -

Contact technique *

-
-
-
- - - @if (fieldInvalid('contactTechnicalName')) { -

Obligatoire.

- } -
-
-
-
- - - @if (fieldInvalid('contactTechnicalEntity')) { -

Obligatoire.

- } -
-
-
-
- - - @if (fieldInvalid('contactTechnicalEmail')) { -

Email valide requis.

- } -
-
-
- -
- - -
-
- } - - - @if (step() === 4) { -
-
-
-

Récapitulatif

-
-
-
Fichier{{ selectedFiles().length > 1 ? 's' : '' }}
-
- @if (selectedFiles().length === 0) { - Aucun fichier - } @else if (selectedFiles().length === 1) { - {{ selectedFiles()[0].name }} - } @else { - @for (f of selectedFiles(); track f.name) { -
- {{ f.name }} - @if (f.name === detectedMainFilename()) { - Principal - } -
- } - } -
-
-
-
Type
-
{{ displayType() }}
-
-
-
Titre
-
{{ previewTitle() }}
-
-
-
Version
-
{{ metaForm.value.versionMajor }}.{{ metaForm.value.versionMinor }}.{{ metaForm.value.versionPatch }}
-
-
-
Fournisseur
-
{{ metaForm.value.provider }}
-
- @if (metaForm.value.categoryId) { -
-
Catégorie
-
{{ selectedCategoryName() }}
-
- } - @if (metaForm.value.description) { -
-
Description
-
{{ metaForm.value.description }}
-
- } -
-
Contact métier
-
- {{ metaForm.value.contactFunctionalName }}
- {{ metaForm.value.contactFunctionalEntity }}
- {{ metaForm.value.contactFunctionalEmail }} -
-
-
-
Contact technique
-
- {{ metaForm.value.contactTechnicalName }}
- {{ metaForm.value.contactTechnicalEntity }}
- {{ metaForm.value.contactTechnicalEmail }} -
-
-
-
-
-
- - @if (uploadError()) { -
-

Erreur lors de l'import

-

{{ uploadError() }}

-
- } - -
- - -
- } -
- `, + templateUrl: "./upload.component.html", }) export class UploadComponent implements OnInit { private fb = inject(FormBuilder);