Show the live alert feed for the selected channel

Angular · Angular · advanced · greenfield

Wires the alerts panel to the live feed: the component watches the channelId route param, and on every change resets the list and subscribes to that channel's alert stream, prepending each incoming alert and keeping the latest 50. The param subscription is scoped with takeUntilDestroyed per our conventions. Tested by opening the ops channel and watching alerts stream in live.

An incident-response dashboard. Channels emit a steady stream of alerts (a busy channel does several per minute); on-call engineers hop between channels constantly during an incident. The panel component stays mounted across switches — routing only rewrites the param.

Requirements

Files touched

--- src/app/alerts/channel-alerts.component.ts
+import { Component, inject, signal } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { AlertFeedService, AlertMessage } from './alert-feed.service';
+
+const MAX_ALERTS = 50;
+
+/**
+ * Live alert feed for the channel in the route. The sidebar switches
+ * channels by rewriting the :channelId param; the panel stays mounted.
+ */
+@Component({
+  selector: 'app-channel-alerts',
+  standalone: true,
+  template: `
+    <section class="alerts" aria-label="Channel alerts">
+      <h2>#{{ channelId() }}</h2>
+      @if (alerts().length === 0) {
+        <p class="alerts-empty">No alerts yet in this channel.</p>
+      } @else {
+        <ul class="alerts-list">
+          @for (alert of alerts(); track alert.id) {
+            <li class="alert-row" [class.critical]="alert.severity === 'critical'">
+              <span class="alert-text">{{ alert.text }}</span>
+              <time [attr.datetime]="alert.receivedAt">{{ alert.receivedAt }}</time>
+            </li>
+          }
+        </ul>
+      }

Review this PR

Angular practice