fix(frontend): traite la revue de phyri0s sur la PR #95
Frontend / build (push) Successful in 9m42s
Frontend / test (push) Failing after 5m23s
Frontend / SonarQube (push) Skipped

- Reutilise .ev-link pour le lien "Detail" de la liste des sites au
  lieu de dupliquer ses regles de style.
- site.location vide est traite comme absent (affiche "-"), pas
  seulement null/undefined.
- siteId de la page detail suit desormais route.paramMap de facon
  reactive plutot qu'une lecture ponctuelle du snapshot, pour rester
  a jour quand Angular reutilise l'instance du composant en changeant
  de site.
- Ajoute provideRouter([]) manquant dans un test dashboard existant,
  necessaire depuis l'ajout du lien "Voir les sites" au rebase sur dev.
This commit is contained in:
Johan LEROY
2026-09-17 16:01:15 +02:00
parent e22feac2c4
commit 8fb5ab9f65
6 changed files with 30 additions and 18 deletions
@@ -164,6 +164,7 @@ describe('Dashboard', () => {
providers: [ providers: [
{ provide: StatsService, useValue: statsMock }, { provide: StatsService, useValue: statsMock },
{ provide: AlertsService, useValue: alertsMock }, { provide: AlertsService, useValue: alertsMock },
provideRouter([]),
], ],
}); });
@@ -9,7 +9,7 @@
<a routerLink="/dashboard" class="ev-brand-link"> <a routerLink="/dashboard" class="ev-brand-link">
<ev-brand class="site-detail-placeholder__logo" /> <ev-brand class="site-detail-placeholder__logo" />
</a> </a>
<h1>Site {{ siteId }}</h1> <h1>Site {{ siteId() }}</h1>
</header> </header>
<ev-card> <ev-card>
@@ -1,17 +1,16 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { ActivatedRoute, convertToParamMap, provideRouter } from '@angular/router'; import { ActivatedRoute, convertToParamMap, provideRouter } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { SiteDetailPlaceholder } from './site-detail-placeholder'; import { SiteDetailPlaceholder } from './site-detail-placeholder';
describe('SiteDetailPlaceholder', () => { describe('SiteDetailPlaceholder', () => {
it("affiche l'identifiant du site depuis la route", () => { it("affiche l'identifiant du site depuis la route", () => {
const paramMap = new BehaviorSubject(convertToParamMap({ siteId: 'SITE001' }));
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [SiteDetailPlaceholder], imports: [SiteDetailPlaceholder],
providers: [ providers: [
provideRouter([]), provideRouter([]),
{ { provide: ActivatedRoute, useValue: { paramMap } },
provide: ActivatedRoute,
useValue: { snapshot: { paramMap: convertToParamMap({ siteId: 'SITE001' }) } },
},
], ],
}); });
@@ -20,4 +19,24 @@ describe('SiteDetailPlaceholder', () => {
expect(fixture.nativeElement.textContent).toContain('SITE001'); expect(fixture.nativeElement.textContent).toContain('SITE001');
}); });
it('met à jour l\'affichage quand le paramètre change sans recréer le composant', () => {
const paramMap = new BehaviorSubject(convertToParamMap({ siteId: 'SITE001' }));
TestBed.configureTestingModule({
imports: [SiteDetailPlaceholder],
providers: [
provideRouter([]),
{ provide: ActivatedRoute, useValue: { paramMap } },
],
});
const fixture = TestBed.createComponent(SiteDetailPlaceholder);
fixture.detectChanges();
paramMap.next(convertToParamMap({ siteId: 'SITE002' }));
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('SITE002');
expect(fixture.nativeElement.textContent).not.toContain('SITE001');
});
}); });
@@ -1,5 +1,7 @@
import { Component, inject } from '@angular/core'; import { Component, inject } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute, RouterLink } from '@angular/router'; import { ActivatedRoute, RouterLink } from '@angular/router';
import { map } from 'rxjs';
import { Card } from '../../../shared/components/ui/card/card'; import { Card } from '../../../shared/components/ui/card/card';
import { Brand } from '../../../shared/components/ui/brand/brand'; import { Brand } from '../../../shared/components/ui/brand/brand';
@@ -13,5 +15,5 @@ import { Brand } from '../../../shared/components/ui/brand/brand';
export class SiteDetailPlaceholder { export class SiteDetailPlaceholder {
private route = inject(ActivatedRoute); private route = inject(ActivatedRoute);
siteId = this.route.snapshot.paramMap.get('siteId'); siteId = toSignal(this.route.paramMap.pipe(map((params) => params.get('siteId'))));
} }
@@ -34,10 +34,10 @@
<tr> <tr>
<td>{{ site.site_name }}</td> <td>{{ site.site_name }}</td>
<td>{{ site.site_type }}</td> <td>{{ site.site_type }}</td>
<td>{{ site.location ?? '-' }}</td> <td>{{ site.location || '-' }}</td>
<td>{{ site.capacity_kw ?? '-' }}</td> <td>{{ site.capacity_kw ?? '-' }}</td>
<td><ev-badge [tone]="badgeToneForStatus(site.status)">{{ site.status ?? '-' }}</ev-badge></td> <td><ev-badge [tone]="badgeToneForStatus(site.status)">{{ site.status ?? '-' }}</ev-badge></td>
<td><a [routerLink]="['/sites', site.site_id]" class="site-list__detail-link">Détail</a></td> <td><a [routerLink]="['/sites', site.site_id]" class="ev-link">Détail</a></td>
</tr> </tr>
} }
</tbody> </tbody>
@@ -61,13 +61,3 @@
border-bottom: none; border-bottom: none;
} }
} }
.site-list__detail-link {
color: var(--color-primary);
font-weight: 600;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}