Refonte qualité (shared / back / front) #1
@@ -14,34 +14,17 @@ import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
|
|||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } 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 { BreadcrumbComponent, BreadcrumbItem } from '../../shared/breadcrumb/breadcrumb.component';
|
||||||
import { ApiEntry, ApiEntryListItem, Category } from '@datacat/shared';
|
import { ApiEntry, ApiEntryListItem, Category } from '@datacat/shared';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-api-detail',
|
selector: 'app-api-detail',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterLink, ReactiveFormsModule],
|
imports: [CommonModule, RouterLink, ReactiveFormsModule, BreadcrumbComponent],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: `
|
template: `
|
||||||
<div class="fr-container fr-mt-4w fr-mb-4w">
|
<div class="fr-container fr-mt-4w fr-mb-4w">
|
||||||
<!-- Fil d'Ariane -->
|
<app-breadcrumb [items]="breadcrumbItems()" />
|
||||||
<nav class="fr-breadcrumb fr-mb-3w" aria-label="vous êtes ici">
|
|
||||||
<ol class="fr-breadcrumb__list">
|
|
||||||
<li>
|
|
||||||
<a class="fr-breadcrumb__link" routerLink="/">Accueil</a>
|
|
||||||
</li>
|
|
||||||
@if (categoryBreadcrumb().length === 0) {
|
|
||||||
<li><a class="fr-breadcrumb__link" routerLink="/browse">Parcourir</a></li>
|
|
||||||
}
|
|
||||||
@for (crumb of categoryBreadcrumb(); track crumb.id) {
|
|
||||||
<li><a class="fr-breadcrumb__link" [routerLink]="['/browse', crumb.id]">{{ crumb.name }}</a></li>
|
|
||||||
}
|
|
||||||
<li>
|
|
||||||
<a class="fr-breadcrumb__link" aria-current="page">
|
|
||||||
{{ api()?.title ?? 'Chargement...' }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
@if (loading()) {
|
@if (loading()) {
|
||||||
<div class="fr-callout fr-mb-4w">
|
<div class="fr-callout fr-mb-4w">
|
||||||
@@ -436,6 +419,15 @@ export class ApiDetailComponent implements OnInit, OnDestroy {
|
|||||||
return ['/browse'];
|
return ['/browse'];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
breadcrumbItems = computed<BreadcrumbItem[]>(() => {
|
||||||
|
const crumbs = this.categoryBreadcrumb();
|
||||||
|
const items: BreadcrumbItem[] = [{ label: 'Accueil', link: '/' }];
|
||||||
|
if (crumbs.length === 0) items.push({ label: 'Parcourir', link: '/browse' });
|
||||||
|
for (const crumb of crumbs) items.push({ label: crumb.name, link: ['/browse', crumb.id] });
|
||||||
|
items.push({ label: this.api()?.title ?? 'Chargement...' });
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
|
||||||
/* Onglets */
|
/* Onglets */
|
||||||
activeTab = signal<'info' | 'contacts'>('info');
|
activeTab = signal<'info' | 'contacts'>('info');
|
||||||
editingInfo = signal(false);
|
editingInfo = signal(false);
|
||||||
|
|||||||
@@ -17,32 +17,16 @@ import { CategoryBrowseResponse, Category, CategoryWithCounts, ApiEntryListItem
|
|||||||
import { forkJoin } from 'rxjs';
|
import { forkJoin } from 'rxjs';
|
||||||
import { CategoryFormModalComponent } from '../../shared/category-form-modal/category-form-modal.component';
|
import { CategoryFormModalComponent } from '../../shared/category-form-modal/category-form-modal.component';
|
||||||
import { CategoryDeleteModalComponent } from '../../shared/category-delete-modal/category-delete-modal.component';
|
import { CategoryDeleteModalComponent } from '../../shared/category-delete-modal/category-delete-modal.component';
|
||||||
|
import { BreadcrumbComponent, BreadcrumbItem } from '../../shared/breadcrumb/breadcrumb.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-browse',
|
selector: 'app-browse',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterLink, CategoryFormModalComponent, CategoryDeleteModalComponent],
|
imports: [CommonModule, RouterLink, CategoryFormModalComponent, CategoryDeleteModalComponent, BreadcrumbComponent],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: `
|
template: `
|
||||||
<div class="fr-container fr-mt-4w fr-mb-4w">
|
<div class="fr-container fr-mt-4w fr-mb-4w">
|
||||||
<!-- Fil d'Ariane -->
|
<app-breadcrumb [items]="breadcrumbItems()" />
|
||||||
<nav class="fr-breadcrumb fr-mb-3w" aria-label="vous êtes ici">
|
|
||||||
<ol class="fr-breadcrumb__list">
|
|
||||||
<li>
|
|
||||||
<a class="fr-breadcrumb__link" routerLink="/">Accueil</a>
|
|
||||||
</li>
|
|
||||||
@for (crumb of ancestors(); track crumb.id) {
|
|
||||||
<li>
|
|
||||||
<a class="fr-breadcrumb__link" [routerLink]="['/browse', crumb.id]">{{ crumb.name }}</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
@if (browseData()?.category) {
|
|
||||||
<li>
|
|
||||||
<a class="fr-breadcrumb__link" aria-current="page">{{ browseData()!.category!.name }}</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- En-tête -->
|
<!-- En-tête -->
|
||||||
@if (categoryId()) {
|
@if (categoryId()) {
|
||||||
@@ -309,6 +293,16 @@ export class BrowseComponent implements OnInit {
|
|||||||
return d.breadcrumb.slice(0, -1);
|
return d.breadcrumb.slice(0, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
breadcrumbItems = computed<BreadcrumbItem[]>(() => {
|
||||||
|
const items: BreadcrumbItem[] = [{ label: 'Accueil', link: '/' }];
|
||||||
|
for (const crumb of this.ancestors()) {
|
||||||
|
items.push({ label: crumb.name, link: ['/browse', crumb.id] });
|
||||||
|
}
|
||||||
|
const current = this.browseData()?.category;
|
||||||
|
if (current) items.push({ label: current.name });
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
|
||||||
backUrl = computed<string[]>(() => {
|
backUrl = computed<string[]>(() => {
|
||||||
const anc = this.ancestors();
|
const anc = this.ancestors();
|
||||||
if (anc.length > 0) return ['/browse', anc[anc.length - 1].id];
|
if (anc.length > 0) return ['/browse', anc[anc.length - 1].id];
|
||||||
|
|||||||
@@ -13,23 +13,17 @@ 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 { BreadcrumbComponent, BreadcrumbItem } from '../../shared/breadcrumb/breadcrumb.component';
|
||||||
import { ApiEntry, ApiEntryListItem, 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',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, ReactiveFormsModule, RouterLink],
|
imports: [CommonModule, ReactiveFormsModule, RouterLink, BreadcrumbComponent],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: `
|
template: `
|
||||||
<div class="fr-container fr-mt-4w fr-mb-4w">
|
<div class="fr-container fr-mt-4w fr-mb-4w">
|
||||||
<!-- Fil d'Ariane -->
|
<app-breadcrumb [items]="breadcrumbItems" />
|
||||||
<nav class="fr-breadcrumb fr-mb-3w" aria-label="vous êtes ici">
|
|
||||||
<ol class="fr-breadcrumb__list">
|
|
||||||
<li><a class="fr-breadcrumb__link" routerLink="/browse">Parcourir</a></li>
|
|
||||||
<li><a class="fr-breadcrumb__link" routerLink="/catalog">Catalogue</a></li>
|
|
||||||
<li><a class="fr-breadcrumb__link" aria-current="page">Importer une API</a></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<h1 class="fr-h2 fr-mb-4w">Importer une API</h1>
|
<h1 class="fr-h2 fr-mb-4w">Importer une API</h1>
|
||||||
|
|
||||||
@@ -511,6 +505,12 @@ export class UploadComponent implements OnInit {
|
|||||||
private destroyRef = inject(DestroyRef);
|
private destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
step = signal(1);
|
step = signal(1);
|
||||||
|
readonly breadcrumbItems: BreadcrumbItem[] = [
|
||||||
|
{ label: 'Parcourir', link: '/browse' },
|
||||||
|
{ label: 'Catalogue', link: '/catalog' },
|
||||||
|
{ label: 'Importer une API' },
|
||||||
|
];
|
||||||
|
|
||||||
private readonly maxFileSize = 5 * 1024 * 1024; // 5 Mo
|
private readonly maxFileSize = 5 * 1024 * 1024; // 5 Mo
|
||||||
selectedFiles = signal<File[]>([]);
|
selectedFiles = signal<File[]>([]);
|
||||||
detectedType = signal<'ASYNCAPI' | 'OPENAPI' | null>(null);
|
detectedType = signal<'ASYNCAPI' | 'OPENAPI' | null>(null);
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
|
||||||
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
|
/** Un maillon du fil d'Ariane. `link` absent => élément courant (aria-current). */
|
||||||
|
export interface BreadcrumbItem {
|
||||||
|
label: string;
|
||||||
|
link?: string | unknown[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fil d'Ariane DSFR générique (présentationnel). Chaque page construit sa liste
|
||||||
|
* d'items et la passe ; le dernier item sans `link` est marqué comme courant.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'app-breadcrumb',
|
||||||
|
standalone: true,
|
||||||
|
imports: [RouterLink],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
template: `
|
||||||
|
<nav class="fr-breadcrumb fr-mb-3w" aria-label="vous êtes ici">
|
||||||
|
<ol class="fr-breadcrumb__list">
|
||||||
|
@for (item of items(); track $index) {
|
||||||
|
<li>
|
||||||
|
@if (item.link) {
|
||||||
|
<a class="fr-breadcrumb__link" [routerLink]="item.link">{{ item.label }}</a>
|
||||||
|
} @else {
|
||||||
|
<a class="fr-breadcrumb__link" aria-current="page">{{ item.label }}</a>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class BreadcrumbComponent {
|
||||||
|
items = input.required<BreadcrumbItem[]>();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user