Files
ENI-projet-piscine/apps/frontend/src/app/shared/components/alert-feed/alert-feed.html
T
Johan LEROY d276070ee2 feat(frontend): widget app-alert-feed filtrable, rafraîchi toutes les 60 s
Flux des alertes actives sur GET /alerts : filtres site et sévérité posés en
paramètres de requête (l'API les accepte), couleur et badge par sévérité, icône
par type, nom du site résolu depuis GET /sites, mesure et seuil avec leur unité.
Rafraîchissement par timer(0, 60 s) relancé à chaque changement de filtre, états
chargement / vide / indisponible, pagination côté client par dix car l'API ne
pagine pas. L'input `siteId` fige le site et masque son filtre, pour la vue
détail d'un site.
2026-09-21 14:29:22 +02:00

96 lines
3.3 KiB
HTML

<section class="alert-feed">
<header class="alert-feed__header">
<div>
<h2 class="alert-feed__title">Alertes actives</h2>
@if (!loading() || alerts().length > 0) {
<p class="alert-feed__count">
{{ alerts().length }} {{ alerts().length > 1 ? 'alertes' : 'alerte' }}
</p>
}
</div>
<div class="alert-feed__filters">
@if (!siteId()) {
<label class="alert-feed__filter">
<span class="form-label">Site</span>
<select class="form-select" data-testid="site-filter" (change)="onSiteChange($event)">
<option value="">Tous les sites</option>
@for (site of sites(); track site.site_id) {
<option [value]="site.site_id">{{ site.site_name }}</option>
}
</select>
</label>
}
<label class="alert-feed__filter">
<span class="form-label">Sévérité</span>
<select
class="form-select"
data-testid="severity-filter"
(change)="onSeverityChange($event)"
>
<option value="">Toutes</option>
@for (severite of severites; track severite) {
<option [value]="severite">{{ severityLabel(severite) }}</option>
}
</select>
</label>
</div>
</header>
@if (error(); as message) {
<ev-alert severity="danger" class="alert-feed__banner">{{ message }}</ev-alert>
}
@if (loading() && alerts().length === 0 && !error()) {
<p class="alert-feed__state" aria-live="polite">Chargement des alertes…</p>
} @else if (alerts().length === 0 && !error()) {
<ev-alert severity="success" class="alert-feed__banner"
>Aucune alerte pour ces critères.</ev-alert
>
}
<ul class="alert-feed__list" [attr.aria-busy]="loading()">
@for (alert of visibleAlerts(); track alert.alert_id) {
<li class="alert-feed__item" [class]="'alert-feed__item--' + alert.severity">
<span class="alert-feed__icon">
<ev-icon [name]="alert.type" [label]="typeLabel(alert.type)" />
</span>
<div class="alert-feed__body">
<div class="alert-feed__meta">
<ev-badge [tone]="toneFor(alert.severity)">{{
severityLabel(alert.severity)
}}</ev-badge>
<span class="alert-feed__type">{{ typeLabel(alert.type) }}</span>
<span class="alert-feed__site">{{ siteName(alert.site_id) }}</span>
<time class="alert-feed__time" [attr.datetime]="alert.timestamp">
{{ alert.timestamp | date: 'dd/MM/yyyy HH:mm' }}
</time>
</div>
<p class="alert-feed__message">{{ alert.message }}</p>
@if (alert.value !== null) {
<p class="alert-feed__values">
<strong>{{ alert.value | number: '1.0-1' }} {{ unitFor(alert.metric) }}</strong>
@if (alert.threshold !== null) {
<span
>seuil {{ alert.threshold | number: '1.0-1' }} {{ unitFor(alert.metric) }}</span
>
}
</p>
}
</div>
</li>
}
</ul>
@if (hiddenCount() > 0) {
<ev-button
variant="secondary"
[fullWidth]="false"
class="alert-feed__more"
data-testid="show-more"
(click)="showMore()"
>
Afficher plus ({{ hiddenCount() }} restantes)
</ev-button>
}
</section>