using ZB.MOM.WW.MxGateway.Contracts.Proto; using ZB.MOM.WW.MxGateway.Server.Alarms; namespace ZB.MOM.WW.MxGateway.Server.Dashboard; /// /// Dashboard projection of an message /// carried on the alarm feed. Maps the protobuf provider mode / degraded /// flag into Bootstrap-only display fields so the Alarms page can render a /// status badge without touching protobuf types. /// public sealed record DashboardAlarmProviderStatus( AlarmProviderMode Mode, bool IsDegraded, string Label, string BadgeCssClass, string Reason, DateTimeOffset? SinceUtc) { /// Badge label shown when the alarm-manager provider is healthy. public const string AlarmManagerLabel = "Alarm Manager"; /// Badge label shown when the feed has fallen back to subtag monitoring. public const string DegradedLabel = "Subtag monitoring (degraded)"; /// /// Badge label shown when the feed is in subtag monitoring because it was /// deliberately configured (Fallback:Mode=ForceSubtag), as opposed /// to an unexpected failover. A stable, intended state rather than a fault. /// public const string ForcedSubtagLabel = "Subtag monitoring (forced)"; /// /// Badge label shown when the alarm manager is serving normally but the subtag standby /// behind it covers nothing — an empty or undiscoverable watch-list. The feed is /// healthy today; what is degraded is the fallback that would take over tomorrow, so the /// badge names the standby rather than claiming the feed has failed over. /// public const string NoSubtagStandbyLabel = "Alarm Manager (no subtag standby)"; private const string HealthyBadge = "bg-success"; private const string DegradedBadge = "bg-warning text-dark"; // Cyan/info badge: visually distinct from the amber failover-degraded badge — // forced subtag is an intentional configuration, not an alarm-manager fault. private const string ForcedSubtagBadge = "bg-info text-dark"; /// /// The default status assumed before the first provider-status message /// arrives: healthy alarm-manager mode. /// public static DashboardAlarmProviderStatus Healthy { get; } = new( Mode: AlarmProviderMode.Alarmmgr, IsDegraded: false, Label: AlarmManagerLabel, BadgeCssClass: HealthyBadge, Reason: string.Empty, SinceUtc: null); /// Projects an alarm-feed provider-status payload into a dashboard badge model. /// The provider-status payload from an . /// The projected dashboard status. public static DashboardAlarmProviderStatus FromProviderStatus(AlarmProviderStatus status) { ArgumentNullException.ThrowIfNull(status); // Treat the explicit degraded flag and the SUBTAG mode as equivalent; // the contract sets degraded=true whenever mode == SUBTAG, but guard // against either being set independently. bool degraded = status.Degraded || status.Mode == AlarmProviderMode.Subtag; string reason = status.Reason ?? string.Empty; // A configured ForceSubtag start carries the well-known forced reason and // is a deliberate mode, not a failover — render it distinctly so an // operator isn't alarmed by a "(degraded)" badge for an intended config. bool forced = degraded && status.Mode == AlarmProviderMode.Subtag && string.Equals(reason, AlarmProviderReasons.ForcedSubtag, StringComparison.Ordinal); // Degraded WITHOUT subtag mode means the alarm manager is still serving and the // standby is the unsound half. "Subtag monitoring (degraded)" would misreport which // provider is live, so this state gets its own label; the amber badge is shared because // the operator action — fix discovery — is equally overdue in both. bool standbyOnlyWarning = degraded && status.Mode != AlarmProviderMode.Subtag; string label = !degraded ? AlarmManagerLabel : standbyOnlyWarning ? NoSubtagStandbyLabel : forced ? ForcedSubtagLabel : DegradedLabel; string badge = !degraded ? HealthyBadge : standbyOnlyWarning ? DegradedBadge : forced ? ForcedSubtagBadge : DegradedBadge; return new DashboardAlarmProviderStatus( Mode: status.Mode, IsDegraded: degraded, Label: label, BadgeCssClass: badge, Reason: reason, SinceUtc: status.Since?.ToDateTimeOffset()); } /// Projects an alarm-feed message into a dashboard badge model. /// An alarm-feed message whose payload is a provider status. /// The projected dashboard status. /// The message does not carry a provider-status payload. public static DashboardAlarmProviderStatus FromFeed(AlarmFeedMessage message) { ArgumentNullException.ThrowIfNull(message); if (message.PayloadCase != AlarmFeedMessage.PayloadOneofCase.ProviderStatus) { throw new ArgumentException( "Alarm-feed message does not carry a provider-status payload.", nameof(message)); } return FromProviderStatus(message.ProviderStatus); } }