docs(frontend): met à jour l'état du frontend et le design système
30-frontend.md : le mode fixtures est inactif dans les deux environnements (la doc affirmait l'inverse), services et pages manquants, widget alertes et états de chargement, strict activé. 32-design-systeme-frontend.md : tokens typographiques, ev-icon, app-alert-feed, classes de tableau.
This commit is contained in:
@@ -4,39 +4,47 @@ Application Angular 22, 100 % standalone, testée avec Vitest. Source dans `apps
|
|||||||
|
|
||||||
## État actuel
|
## État actuel
|
||||||
|
|
||||||
Statut : `En cours`. L'application sert une première page métier, le tableau de bord, alimentée
|
Statut : `En cours`. L'application sert le tableau de bord, la liste et le détail des sites, la
|
||||||
par des fixtures : les endpoints qu'elle appelle n'existent pas encore côté API.
|
supervision des capteurs (admin) et le flux des alertes actives, tous branchés sur l'API réelle.
|
||||||
|
|
||||||
Ce qui est en place :
|
Ce qui est en place :
|
||||||
|
|
||||||
- Bootstrap par `bootstrapApplication(App, appConfig)`, **aucun `NgModule`** dans le dépôt.
|
- Bootstrap par `bootstrapApplication(App, appConfig)`, **aucun `NgModule`** dans le dépôt.
|
||||||
- `app.config.ts` fournit `provideBrowserGlobalErrorListeners()`, `provideRouter(routes)` et
|
- `app.config.ts` fournit `provideBrowserGlobalErrorListeners()`, `provideRouter(routes)` et
|
||||||
`provideHttpClient(withInterceptors([mockApiInterceptor]))`.
|
`provideHttpClient(withInterceptors([authInterceptor, mockApiInterceptor]))`.
|
||||||
- Une route `/dashboard` en composant différé, et une redirection depuis la racine.
|
- Des routes en composants différés (`/dashboard`, `/sites`, `/sites/:siteId`,
|
||||||
- `core/services` porte `StatsService`, `AlertsService`, `PredictionsService`, `SitesService` et
|
`/monitoring/sensors` réservée au rôle `admin`) et une redirection depuis la racine.
|
||||||
`AuthService`, `core/interceptors` l'intercepteur de fixtures et l'intercepteur d'authentification
|
- `core/services` porte un service HTTP par domaine (`StatsService`, `AlertsService` avec ses
|
||||||
(jeton porteur, rafraîchissement sur 401), `core/guards` la garde de route `authGuard`,
|
filtres `site_id` et `severity`, `PredictionsService`, `SitesService`, `ReadingsService`,
|
||||||
`features/dashboard` la page principale, `shared/components` la jauge de consommation et le
|
`SensorsService`, `AuthService`), `core/interceptors` l'intercepteur de fixtures et l'intercepteur
|
||||||
graphique de charge par site, tous deux construits sur Chart.js.
|
d'authentification (jeton porteur, rafraîchissement sur 401), `core/guards` la garde `authGuard`.
|
||||||
|
- `features/` porte une page par domaine. `shared/components` porte la jauge de consommation et
|
||||||
|
les graphiques Chart.js, le widget `app-alert-feed` (flux d'alertes filtrable par site et
|
||||||
|
sévérité, rafraîchi toutes les 60 s, première vue de l'application avec des états chargement /
|
||||||
|
vide / indisponible) et, dans `shared/models`, des types alignés sur les schémas Pydantic du
|
||||||
|
backend, plus les tables de présentation partagées (`alert-presentation.ts` : ton, libellé et
|
||||||
|
unité par sévérité, type et métrique).
|
||||||
- Une authentification complète côté interface : connexion, mot de passe oublié/réinitialisation,
|
- Une authentification complète côté interface : connexion, mot de passe oublié/réinitialisation,
|
||||||
changement de mot de passe, garde de route sur `/dashboard` et `/sites`. Détail :
|
changement de mot de passe, garde de route sur toute la zone authentifiée. Détail :
|
||||||
[31-contrat-authentification.md](31-contrat-authentification.md).
|
[31-contrat-authentification.md](31-contrat-authentification.md).
|
||||||
- Un système de design partagé (`shared/components/ui/` : `ev-button`, `ev-card`, `ev-alert`,
|
- Un système de design partagé (`shared/components/ui/` : `ev-button`, `ev-card`, `ev-alert`,
|
||||||
`ev-badge`, `ev-brand`, tokens CSS dans `styles/_tokens.scss`) que toute nouvelle page doit
|
`ev-badge`, `ev-brand`, `ev-icon`, tokens CSS dans `styles/_tokens.scss`, classes globales de
|
||||||
réutiliser plutôt que redéfinir ses propres styles. Détail :
|
formulaire, de navigation et de tableau) que toute nouvelle page doit réutiliser plutôt que
|
||||||
|
redéfinir ses propres styles. Détail :
|
||||||
[32-design-systeme-frontend.md](32-design-systeme-frontend.md).
|
[32-design-systeme-frontend.md](32-design-systeme-frontend.md).
|
||||||
- L'état vit dans des signaux, sans bibliothèque dédiée.
|
- L'état vit dans des signaux, sans bibliothèque dédiée.
|
||||||
|
- TypeScript en `"strict": true` ; `strictTemplates` n'est pas encore activé.
|
||||||
- Vitest via le builder `@angular/build:unit-test`, couverture activée.
|
- Vitest via le builder `@angular/build:unit-test`, couverture activée.
|
||||||
- Prettier configuré, parser `angular` pour les gabarits HTML.
|
- Prettier configuré, parser `angular` pour les gabarits HTML.
|
||||||
|
|
||||||
Ce qui n'existe pas encore :
|
Ce qui n'existe pas encore :
|
||||||
|
|
||||||
- **`stats`/`alerts` restent sur fixtures.** `GET /api/v1/stats/summary` et `GET /api/v1/alerts`
|
- **Le mode fixtures est inactif.** `useMockFixtures` vaut `false` dans `environment.ts` comme dans
|
||||||
sont servis par l'intercepteur de fixtures ; l'API expose bien ces routes désormais, mais rien
|
`environment.development.ts` : `mockApiInterceptor` ne sert `/stats/summary` et `/alerts` que
|
||||||
ne bascule `useMockFixtures` à `false` en développement pour les consommer réellement.
|
dans son propre spec. En développement, toutes les pages exigent un backend joignable et un jeton
|
||||||
`GET /api/v1/predictions` fait exception : jamais mocké, branché sur l'API réelle depuis cette
|
valide.
|
||||||
PR (voir plus bas).
|
- Un état de chargement généralisé : seul `app-alert-feed` en a un, les autres pages restent vides
|
||||||
- Aucun état de chargement : tant que la première réponse n'est pas arrivée, la page reste vide.
|
tant que la première réponse n'est pas arrivée.
|
||||||
- Aucun lint : ESLint n'est pas installé.
|
- Aucun lint : ESLint n'est pas installé.
|
||||||
|
|
||||||
## Arborescence
|
## Arborescence
|
||||||
@@ -87,11 +95,11 @@ sequenceDiagram
|
|||||||
```
|
```
|
||||||
|
|
||||||
`mockApiInterceptor` n'intercepte que `/stats/summary` et `/alerts`, et seulement si
|
`mockApiInterceptor` n'intercepte que `/stats/summary` et `/alerts`, et seulement si
|
||||||
`environment.useMockFixtures` est vrai. Le drapeau est à `true` en développement, à `false` en
|
`environment.useMockFixtures` est vrai. Le drapeau vaut `false` dans les deux fichiers
|
||||||
production : toute autre requête, et toutes les requêtes en production, suivent le chemin réel.
|
d'environnement : en pratique toutes les requêtes suivent le chemin réel et l'intercepteur n'est
|
||||||
`/predictions` est volontairement exclu de cette liste (contrairement à `stats`/`alerts`) : il
|
exercé que par son spec. `/predictions` et `/auth/*` ne sont de toute façon jamais mockés. En
|
||||||
suit toujours le chemin réel, comme `/auth/*` - en développement, ça veut dire qu'un jeton valide
|
développement, un jeton valide et un backend joignable sont donc nécessaires pour que le tableau de
|
||||||
et un backend joignable sont nécessaires pour que la section prévisions du dashboard s'affiche.
|
bord s'affiche.
|
||||||
|
|
||||||
En développement, `proxy.conf.json` redirige tout `/api` vers `http://localhost:8000`. C'est ce
|
En développement, `proxy.conf.json` redirige tout `/api` vers `http://localhost:8000`. C'est ce
|
||||||
qui évite le CORS sur le poste, et c'est pourquoi `environment.development.ts` se contente d'un
|
qui évite le CORS sur le poste, et c'est pourquoi `environment.development.ts` se contente d'un
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ seule fois dans `src/styles.scss`. Disponibles partout sans import supplémentai
|
|||||||
| `--color-success` / `-bg`, `--color-warning` / `-bg` / `-text`, `--color-danger` / `-hover` / `-bg` / `-border`, `--color-critical` | États sémantiques (alertes, badges) |
|
| `--color-success` / `-bg`, `--color-warning` / `-bg` / `-text`, `--color-danger` / `-hover` / `-bg` / `-border`, `--color-critical` | États sémantiques (alertes, badges) |
|
||||||
| `--color-text-inverse` | Texte sur fond coloré plein (boutons/badges) |
|
| `--color-text-inverse` | Texte sur fond coloré plein (boutons/badges) |
|
||||||
| `--font-family` | Police unique de l'application |
|
| `--font-family` | Police unique de l'application |
|
||||||
|
| `--font-size-xs` à `--font-size-2xl` | Échelle typographique (0.75rem à 2.25rem) : libellés, corps, titres, grands nombres |
|
||||||
| `--radius-sm`, `--radius-md`, `--radius-pill` | Rayons de bordure (input/bouton, carte, pastille) |
|
| `--radius-sm`, `--radius-md`, `--radius-pill` | Rayons de bordure (input/bouton, carte, pastille) |
|
||||||
| `--shadow-card` | Ombre portée des cartes |
|
| `--shadow-card`, `--shadow-card-hover` | Ombre portée des cartes, au repos et au survol |
|
||||||
| `--space-1` à `--space-5` | Échelle d'espacement (0.35rem à 2.5rem) |
|
| `--space-1` à `--space-5` | Échelle d'espacement (0.35rem à 2.5rem) |
|
||||||
|
|
||||||
Les classes de formulaire partagées (`.form-label`, `.form-input`, `.form-select`, `.form-hint`)
|
Les classes de formulaire partagées (`.form-label`, `.form-input`, `.form-select`, `.form-hint`)
|
||||||
@@ -84,6 +85,23 @@ dans le tableau `imports` du composant qui l'utilise.
|
|||||||
```html
|
```html
|
||||||
<ev-brand />
|
<ev-brand />
|
||||||
```
|
```
|
||||||
|
- **`<ev-icon>`** (`icon/`) : `name` (obligatoire : `spike` / `threshold` / `anomaly` / `outage` /
|
||||||
|
`sensor`, les types d'alerte du contrat) et `label` (facultatif). SVG inline en trait sur
|
||||||
|
`currentColor`, dimensionné par `font-size` comme `ev-brand`. Sans `label` l'icône est décorative
|
||||||
|
(`aria-hidden`) ; avec, elle porte `role="img"` et `aria-label`. Pas de bibliothèque d'icônes : la
|
||||||
|
CSP du reverse proxy (`script-src 'self'`) interdit les scripts tiers, pas le SVG inline.
|
||||||
|
```html
|
||||||
|
<ev-icon name="spike" label="Pic de consommation" />
|
||||||
|
```
|
||||||
|
- **`<app-alert-feed>`** (`shared/components/alert-feed/`) : widget métier plutôt qu'atome du kit,
|
||||||
|
mais réutilisable tel quel. Input `siteId` (facultatif : fige le site et masque son filtre). Il
|
||||||
|
porte ses filtres (`.form-select`), ses états et son rafraîchissement ; le parent ne fait que le
|
||||||
|
poser dans une section.
|
||||||
|
|
||||||
|
Les classes de tableau partagées sont dans `apps/frontend/src/styles/_tables.scss`, importées
|
||||||
|
globalement : `.ev-table-card` sur la `<ev-card>` qui enveloppe un tableau (padding nul),
|
||||||
|
`.ev-table` sur le `<table>`, `.ev-table__number` pour une cellule numérique en chiffres
|
||||||
|
tabulaires, `.ev-table__muted` pour une cellule sans valeur.
|
||||||
|
|
||||||
## Logo
|
## Logo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user