feat(sms): NotificationListForm adapter-gated Type selector + per-type recipients (S7)

This commit is contained in:
Joseph Doherty
2026-06-19 10:38:29 -04:00
parent 4555a3f333
commit f0c69aad83
6 changed files with 373 additions and 15 deletions
@@ -0,0 +1,21 @@
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
/// <summary>
/// Exposes the set of notification delivery channels that actually have a registered
/// delivery adapter, so the Central UI never offers a notification-list Type that the
/// central node cannot deliver. The list is derived from the registered
/// <see cref="ZB.MOM.WW.ScadaBridge.NotificationOutbox.Delivery.INotificationDeliveryAdapter"/>
/// set (each adapter handles a single <see cref="NotificationType"/>) rather than from
/// the <see cref="NotificationType"/> enum, so adding/removing an adapter changes the UI
/// options automatically.
/// </summary>
public interface INotificationChannelCatalog
{
/// <summary>
/// The distinct notification channels that have a registered delivery adapter,
/// in a stable order. Never empty in a correctly configured central node.
/// </summary>
IReadOnlyList<NotificationType> SupportedChannels { get; }
}
@@ -0,0 +1,36 @@
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
using ZB.MOM.WW.ScadaBridge.NotificationOutbox.Delivery;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
/// <summary>
/// Default <see cref="INotificationChannelCatalog"/> that derives the supported channels
/// from the registered <see cref="INotificationDeliveryAdapter"/> set. The central Host
/// registers the Email + SMS adapters (see <c>AddNotificationOutbox</c>) into the same DI
/// container that hosts the Central UI, so projecting each adapter's
/// <see cref="INotificationDeliveryAdapter.Type"/> yields exactly the channels the central
/// node can actually deliver — no hardcoded <c>{Email, Sms}</c> list to drift.
/// </summary>
public sealed class NotificationChannelCatalog : INotificationChannelCatalog
{
/// <summary>
/// Initializes the catalog from the registered delivery adapters, snapshotting the
/// distinct channel set once (the adapter registrations are fixed for the process
/// lifetime). Ordering follows the <see cref="NotificationType"/> enum so the UI Type
/// selector renders in a stable order regardless of adapter registration order.
/// </summary>
/// <param name="adapters">The registered delivery adapters (one per channel).</param>
public NotificationChannelCatalog(IEnumerable<INotificationDeliveryAdapter> adapters)
{
ArgumentNullException.ThrowIfNull(adapters);
SupportedChannels = adapters
.Select(a => a.Type)
.Distinct()
.OrderBy(t => (int)t)
.ToArray();
}
/// <inheritdoc />
public IReadOnlyList<NotificationType> SupportedChannels { get; }
}