From 777cd0ac64186c0f1958edac3a1981fe4870abf0 Mon Sep 17 00:00:00 2001 From: Johan LEROY Date: Mon, 21 Sep 2026 11:38:43 +0200 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20affiche=20since=20comme=20la?= =?UTF-8?q?=20derni=C3=A8re=20lecture=20re=C3=A7ue,=20pas=20comme=20un=20d?= =?UTF-8?q?=C3=A9but=20de=20panne?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le schéma backend dit que since est l'horodatage de la dernière lecture du site, identique pour tous ses capteurs en panne et sans rapport avec le début de la panne. Le template annonçait « depuis », ce que l'exploitant lit comme une date de début de panne. Un site sans aucune lecture renvoie ses cinq capteurs en échec avec since à null : le template affichait « depuis » suivi d'une chaîne vide. Ce cas dit maintenant « aucune lecture reçue ». Format de date explicite plutôt que 'short' : aucune locale n'est enregistrée dans app.config.ts, donc 'short' rendait la date au format en-US. --- apps/frontend/src/app/app.routes.ts | 12 ++--- .../src/app/features/dashboard/dashboard.html | 2 +- .../sensor-status/sensor-status.html | 14 ++--- .../sensor-status/sensor-status.spec.ts | 51 ++++++++++++++----- 4 files changed, 52 insertions(+), 27 deletions(-) diff --git a/apps/frontend/src/app/app.routes.ts b/apps/frontend/src/app/app.routes.ts index de0315f..40e814f 100644 --- a/apps/frontend/src/app/app.routes.ts +++ b/apps/frontend/src/app/app.routes.ts @@ -24,10 +24,10 @@ export const routes: Routes = [ import('./features/sites/site-detail/site-detail').then((m) => m.SiteDetail), }, { - path: 'monitoring/sensors', - canActivate: [authGuard], - data: { role: 'admin' }, - loadComponent: () => - import('./features/monitoring/sensor-status/sensor-status').then((m) => m.SensorStatusView), -}, + path: 'monitoring/sensors', + canActivate: [authGuard], + data: { role: 'admin' }, + loadComponent: () => + import('./features/monitoring/sensor-status/sensor-status').then((m) => m.SensorStatusView), + }, ]; diff --git a/apps/frontend/src/app/features/dashboard/dashboard.html b/apps/frontend/src/app/features/dashboard/dashboard.html index 2f48539..f9a3fb2 100644 --- a/apps/frontend/src/app/features/dashboard/dashboard.html +++ b/apps/frontend/src/app/features/dashboard/dashboard.html @@ -12,7 +12,7 @@
@if (auth.principal()?.role === 'admin') { Supervision des capteurs - } + } Voir les sites @for (entry of sensorEntries; track entry[0]) { + @let diagnostic = sensorOf(site.sensors, entry[0]);
  • - + {{ entry[1] }} - @if (sensorOf(site.sensors, entry[0]).status === 'failing') { + @if (diagnostic.status === 'failing') { - depuis {{ sensorOf(site.sensors, entry[0]).since | date: 'short' }} + @if (diagnostic.since; as since) { + dernière lecture le {{ since | date: 'dd/MM/yyyy HH:mm' }} + } @else { + aucune lecture reçue + } }
  • diff --git a/apps/frontend/src/app/features/monitoring/sensor-status/sensor-status.spec.ts b/apps/frontend/src/app/features/monitoring/sensor-status/sensor-status.spec.ts index 189e241..2e6e84e 100644 --- a/apps/frontend/src/app/features/monitoring/sensor-status/sensor-status.spec.ts +++ b/apps/frontend/src/app/features/monitoring/sensor-status/sensor-status.spec.ts @@ -79,21 +79,44 @@ describe('SensorStatusView', () => { expect(component.sensorOf(OK_SENSORS, 'temperature')).toEqual({ status: 'ok', since: null }); }); - it('affiche la date depuis quand un capteur est en panne', () => { - const sensors: SiteSensors = { - ...OK_SENSORS, - temperature: { status: 'failing', since: '2026-09-18T08:00:00' }, - }; - sensorsMock.getStatus.mockReturnValue( - of({ - timestamp: '2026-09-18T08:00:00', - sites: [{ site_id: 'SITE001', site_name: 'Bureau Test', overall: 'degraded', sensors }], - }) - ); + it('affiche la date de la dernière lecture reçue pour un capteur en panne', () => { + const sensors: SiteSensors = { + ...OK_SENSORS, + temperature: { status: 'failing', since: '2026-09-18T08:00:00' }, + }; + sensorsMock.getStatus.mockReturnValue( + of({ + timestamp: '2026-09-18T08:00:00', + sites: [{ site_id: 'SITE001', site_name: 'Bureau Test', overall: 'degraded', sensors }], + }) + ); - const fixture = TestBed.createComponent(SensorStatusView); - fixture.detectChanges(); + const fixture = TestBed.createComponent(SensorStatusView); + fixture.detectChanges(); - expect(fixture.nativeElement.textContent).toContain('depuis'); + expect(fixture.nativeElement.textContent).toContain('dernière lecture le'); + expect(fixture.nativeElement.textContent).toContain('18/09/2026 08:00'); + }); + + it("annonce l'absence de lecture quand un site n'en a jamais reçu", () => { + const sensors: SiteSensors = { + consumption: { status: 'failing', since: null }, + electrical: { status: 'failing', since: null }, + temperature: { status: 'failing', since: null }, + humidity: { status: 'failing', since: null }, + network: { status: 'failing', since: null }, + }; + sensorsMock.getStatus.mockReturnValue( + of({ + timestamp: '2026-09-18T08:00:00', + sites: [{ site_id: 'SITE001', site_name: 'Bureau Test', overall: 'critical', sensors }], + }) + ); + + const fixture = TestBed.createComponent(SensorStatusView); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toContain('aucune lecture reçue'); + expect(fixture.nativeElement.textContent).not.toContain('dernière lecture le'); }); });