diff --git a/apps/frontend/src/app/app.config.ts b/apps/frontend/src/app/app.config.ts index d89a118..ff4cafd 100644 --- a/apps/frontend/src/app/app.config.ts +++ b/apps/frontend/src/app/app.config.ts @@ -1,12 +1,13 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; -import {mockApiInterceptor} from './core/interceptors/mock-api-interceptor'; -import {provideHttpClient, withInterceptors} from '@angular/common/http'; +import { mockApiInterceptor } from './core/interceptors/mock-api-interceptor'; +import { provideHttpClient, withInterceptors } from '@angular/common/http'; export const appConfig: ApplicationConfig = { providers: [ - provideBrowserGlobalErrorListeners(), provideRouter(routes), + provideBrowserGlobalErrorListeners(), + provideRouter(routes), provideHttpClient(withInterceptors([mockApiInterceptor])), ], }; diff --git a/apps/frontend/src/app/app.routes.ts b/apps/frontend/src/app/app.routes.ts index 9852e8b..8f2739c 100644 --- a/apps/frontend/src/app/app.routes.ts +++ b/apps/frontend/src/app/app.routes.ts @@ -2,5 +2,8 @@ import { Routes } from '@angular/router'; export const routes: Routes = [ { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, - { path: 'dashboard', loadComponent: () => import('./features/dashboard/dashboard').then(m => m.Dashboard) }, + { + path: 'dashboard', + loadComponent: () => import('./features/dashboard/dashboard').then((m) => m.Dashboard), + }, ]; diff --git a/apps/frontend/src/app/core/interceptors/mock-api-interceptor.spec.ts b/apps/frontend/src/app/core/interceptors/mock-api-interceptor.spec.ts index 34a58b2..5d6e343 100644 --- a/apps/frontend/src/app/core/interceptors/mock-api-interceptor.spec.ts +++ b/apps/frontend/src/app/core/interceptors/mock-api-interceptor.spec.ts @@ -33,7 +33,7 @@ describe('mockApiInterceptor', () => { httpMock.expectNone(`${environment.apiUrl}/stats/summary`); expect((result as typeof STATS_SUMMARY_FIXTURE).total_sites).toBe( - STATS_SUMMARY_FIXTURE.total_sites + STATS_SUMMARY_FIXTURE.total_sites, ); }); @@ -56,12 +56,12 @@ describe('mockApiInterceptor', () => { }); it('renvoie la fixture des alertes sans appel réseau quand useMockFixtures est activé', () => { - environment.useMockFixtures = true; - let result: unknown; + environment.useMockFixtures = true; + let result: unknown; - http.get(`${environment.apiUrl}/alerts`).subscribe((r) => (result = r)); + http.get(`${environment.apiUrl}/alerts`).subscribe((r) => (result = r)); - httpMock.expectNone(`${environment.apiUrl}/alerts`); - expect((result as unknown[]).length).toBeGreaterThan(0); -}); + httpMock.expectNone(`${environment.apiUrl}/alerts`); + expect((result as unknown[]).length).toBeGreaterThan(0); + }); }); diff --git a/apps/frontend/src/app/core/mocks/stats-summary.fixture.ts b/apps/frontend/src/app/core/mocks/stats-summary.fixture.ts index 7057fb8..f71a41b 100644 --- a/apps/frontend/src/app/core/mocks/stats-summary.fixture.ts +++ b/apps/frontend/src/app/core/mocks/stats-summary.fixture.ts @@ -18,7 +18,7 @@ export const STATS_SUMMARY_FIXTURE: StatsSummary = { { site_id: 'SITE002', site_name: 'Usine Lyon Vénissieux', - current_consumption_kw: 542.10, + current_consumption_kw: 542.1, capacity_kw: 1000, load_percent: 54.2, data_quality: 'good', diff --git a/apps/frontend/src/app/features/dashboard/dashboard.html b/apps/frontend/src/app/features/dashboard/dashboard.html index d324c74..a64d5d9 100644 --- a/apps/frontend/src/app/features/dashboard/dashboard.html +++ b/apps/frontend/src/app/features/dashboard/dashboard.html @@ -12,8 +12,14 @@
Consommation vs capacité - - {{ s.total_consumption_kw | number:'1.0-1' }} / {{ s.total_capacity_kw | number }} kW + + {{ s.total_consumption_kw | number: '1.0-1' }} / + {{ s.total_capacity_kw | number }} kW
diff --git a/apps/frontend/src/app/features/dashboard/dashboard.scss b/apps/frontend/src/app/features/dashboard/dashboard.scss index 3cacb0f..01cc3a3 100644 --- a/apps/frontend/src/app/features/dashboard/dashboard.scss +++ b/apps/frontend/src/app/features/dashboard/dashboard.scss @@ -131,9 +131,15 @@ h2 { flex-shrink: 0; } -.alert-item--high .alert-item__badge { background: var(--color-degraded); } -.alert-item--medium .alert-item__badge { background: var(--color-partial); } -.alert-item--low .alert-item__badge { background: var(--color-good); } +.alert-item--high .alert-item__badge { + background: var(--color-degraded); +} +.alert-item--medium .alert-item__badge { + background: var(--color-partial); +} +.alert-item--low .alert-item__badge { + background: var(--color-good); +} .alert-item__message { font-size: 0.9rem; diff --git a/apps/frontend/src/app/features/dashboard/dashboard.spec.ts b/apps/frontend/src/app/features/dashboard/dashboard.spec.ts index f55adac..89a69ec 100644 --- a/apps/frontend/src/app/features/dashboard/dashboard.spec.ts +++ b/apps/frontend/src/app/features/dashboard/dashboard.spec.ts @@ -43,7 +43,7 @@ describe('Dashboard', () => { expect(fixture.componentInstance.error()).toBeNull(); }); - it('signale l\'indisponibilité puis repart au rafraîchissement suivant', () => { + it("signale l'indisponibilité puis repart au rafraîchissement suivant", () => { vi.useFakeTimers(); const statsMock = { getSummary: vi diff --git a/apps/frontend/src/app/features/dashboard/dashboard.ts b/apps/frontend/src/app/features/dashboard/dashboard.ts index b6a7627..7733230 100644 --- a/apps/frontend/src/app/features/dashboard/dashboard.ts +++ b/apps/frontend/src/app/features/dashboard/dashboard.ts @@ -40,9 +40,9 @@ export class Dashboard implements OnInit { timer(0, REFRESH_INTERVAL_MS) .pipe( switchMap(() => - this.statsService.getSummary().pipe(catchError(() => this.reportUnavailable())) + this.statsService.getSummary().pipe(catchError(() => this.reportUnavailable())), ), - takeUntilDestroyed(this.destroyRef) + takeUntilDestroyed(this.destroyRef), ) .subscribe((stats) => { this.error.set(null); diff --git a/apps/frontend/src/app/shared/components/consumption-gauge/consumption-gauge.spec.ts b/apps/frontend/src/app/shared/components/consumption-gauge/consumption-gauge.spec.ts index be25fb1..672d50f 100644 --- a/apps/frontend/src/app/shared/components/consumption-gauge/consumption-gauge.spec.ts +++ b/apps/frontend/src/app/shared/components/consumption-gauge/consumption-gauge.spec.ts @@ -32,17 +32,17 @@ describe('ConsumptionGauge', () => { expect(() => fixture.detectChanges()).not.toThrow(); }); it('met à jour le graphique quand les valeurs changent après initialisation', () => { - TestBed.configureTestingModule({ imports: [ConsumptionGauge] }); - const fixture = TestBed.createComponent(ConsumptionGauge); - fixture.componentRef.setInput('consumption', 300); - fixture.componentRef.setInput('capacity', 1000); - fixture.detectChanges(); // déclenche ngAfterViewInit, this.chart existe désormais + TestBed.configureTestingModule({ imports: [ConsumptionGauge] }); + const fixture = TestBed.createComponent(ConsumptionGauge); + fixture.componentRef.setInput('consumption', 300); + fixture.componentRef.setInput('capacity', 1000); + fixture.detectChanges(); // déclenche ngAfterViewInit, this.chart existe désormais - fixture.componentRef.setInput('consumption', 500); - fixture.detectChanges(); // ré-exécute l'effect, cette fois avec this.chart défini + fixture.componentRef.setInput('consumption', 500); + fixture.detectChanges(); // ré-exécute l'effect, cette fois avec this.chart défini - expect(() => fixture.detectChanges()).not.toThrow(); -}); + expect(() => fixture.detectChanges()).not.toThrow(); + }); it('détruit le graphique quand le composant est détruit', () => { TestBed.configureTestingModule({ imports: [ConsumptionGauge] }); diff --git a/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.spec.ts b/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.spec.ts index 0d5944d..59e6b6b 100644 --- a/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.spec.ts +++ b/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.spec.ts @@ -28,25 +28,46 @@ describe('SiteLoadChart', () => { TestBed.configureTestingModule({ imports: [SiteLoadChart] }); const fixture = TestBed.createComponent(SiteLoadChart); fixture.componentRef.setInput('sites', [ - { site_id: 'S1', site_name: 'Test', current_consumption_kw: 50, capacity_kw: 100, load_percent: 50, data_quality: 'good' }, + { + site_id: 'S1', + site_name: 'Test', + current_consumption_kw: 50, + capacity_kw: 100, + load_percent: 50, + data_quality: 'good', + }, ]); expect(() => fixture.detectChanges()).not.toThrow(); }); it('met à jour le graphique quand les sites changent après initialisation', () => { - TestBed.configureTestingModule({ imports: [SiteLoadChart] }); - const fixture = TestBed.createComponent(SiteLoadChart); - fixture.componentRef.setInput('sites', [ - { site_id: 'S1', site_name: 'A', current_consumption_kw: 50, capacity_kw: 100, load_percent: 50, data_quality: 'good' }, - ]); - fixture.detectChanges(); // déclenche ngAfterViewInit, this.chart existe désormais + TestBed.configureTestingModule({ imports: [SiteLoadChart] }); + const fixture = TestBed.createComponent(SiteLoadChart); + fixture.componentRef.setInput('sites', [ + { + site_id: 'S1', + site_name: 'A', + current_consumption_kw: 50, + capacity_kw: 100, + load_percent: 50, + data_quality: 'good', + }, + ]); + fixture.detectChanges(); // déclenche ngAfterViewInit, this.chart existe désormais - fixture.componentRef.setInput('sites', [ - { site_id: 'S2', site_name: 'B', current_consumption_kw: 80, capacity_kw: 100, load_percent: 80, data_quality: 'critical' }, - ]); - fixture.detectChanges(); // ré-exécute l'effect, cette fois avec this.chart défini + fixture.componentRef.setInput('sites', [ + { + site_id: 'S2', + site_name: 'B', + current_consumption_kw: 80, + capacity_kw: 100, + load_percent: 80, + data_quality: 'critical', + }, + ]); + fixture.detectChanges(); // ré-exécute l'effect, cette fois avec this.chart défini - expect(() => fixture.detectChanges()).not.toThrow(); -}); + expect(() => fixture.detectChanges()).not.toThrow(); + }); it('détruit le graphique quand le composant est détruit', () => { TestBed.configureTestingModule({ imports: [SiteLoadChart] }); diff --git a/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.ts b/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.ts index 017ce1b..6c17803 100644 --- a/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.ts +++ b/apps/frontend/src/app/shared/components/site-load-chart/site-load-chart.ts @@ -37,7 +37,9 @@ export class SiteLoadChart implements AfterViewInit, OnDestroy { if (this.chart) { this.chart.data.labels = sites.map((s) => s.site_name); this.chart.data.datasets[0].data = sites.map((s) => s.load_percent ?? 0); - this.chart.data.datasets[0].backgroundColor = sites.map((s) => QUALITY_COLORS[s.data_quality]); + this.chart.data.datasets[0].backgroundColor = sites.map( + (s) => QUALITY_COLORS[s.data_quality], + ); this.chart.update('none'); } });