Files
lmxopcua/src/Core/ZB.MOM.WW.OtOpcUa.Commons/OpcUa/AlarmCommand.cs
T
Joseph Doherty 370a2b7b48 feat(alerts): AdminUI alarm ack/shelve via AdminOperationsActor singleton
T21: add an AdminUI path for acknowledging/shelving alarms that routes
through the admin-pinned AdminOperationsActor cluster singleton, which
republishes onto the same 'alarm-commands' DPS topic the OPC UA method
path (T18) and the engine subscriber (T19) use. The broadcast + the
ScriptedAlarmHostActor ownership filter handle cross-node routing, so
the singleton needs no knowledge of which node owns the alarm.

- Commons: AcknowledgeAlarmCommand/ShelveAlarmCommand (+ result records)
  and a shared AlarmCommandsTopic const; ScriptedAlarmHostActor now
  re-exports that const (mirrors the DriverControlTopic pattern).
- AdminOperationsActor: two handlers map the control-plane messages to
  AlarmCommand (Acknowledge / OneShotShelve / TimedShelve / Unshelve,
  threading User/Comment/UnshelveAtUtc) and publish via the DPS mediator.
- IAdminOperationsClient + AdminOperationsClient: typed Acknowledge/Shelve
  ask wrappers mirroring StartDeploymentAsync.
- Alerts.razor: per-row DriverOperator-gated Ack/Shelve/Unshelve controls;
  operator name from AuthenticationState. Timed-shelve datetime UI deferred.
- 5 TestKit tests (mediator-probe subscribed to alarm-commands) verifying
  each kind's mapping + reply; 56/56 ControlPlane tests green.
2026-06-11 06:44:27 -04:00

55 lines
3.0 KiB
C#

namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa;
/// <summary>
/// Shared DPS topic for inbound alarm commands (<see cref="AlarmCommand"/>). Publishers — the
/// OPC UA node-manager seam (T18) and the AdminUI path via <c>AdminOperationsActor</c> (T21) —
/// and the subscriber (<c>ScriptedAlarmHostActor</c>, T19) reference this single constant so a
/// rename can't silently desynchronise them. Mirrors the
/// <see cref="Messages.Admin.DriverControlTopic"/> pattern; <c>ScriptedAlarmHostActor</c>
/// re-exports this as its <c>AlarmCommandsTopic</c> const.
/// </summary>
public static class AlarmCommandsTopic
{
/// <summary>The cluster DistributedPubSub topic name inbound alarm commands are published on.</summary>
public const string Name = "alarm-commands";
}
/// <summary>
/// Commons-level command carried from an inbound OPC UA Part 9 alarm method call
/// (Acknowledge / Confirm / Shelve / AddComment …) back to the scripted-alarm engine. The SDK
/// node manager builds one of these in its condition method-handler delegates after the
/// <c>AlarmAck</c> role gate passes, then the host routes it onto the cluster
/// <c>alarm-commands</c> DistributedPubSub topic; T19's engine-side subscriber consumes it and
/// drives the matching <c>Part9StateMachine.Apply*</c> transition. This is a pure DTO — it makes
/// no auth decision and holds no SDK/Akka handle.
/// </summary>
/// <param name="AlarmId">
/// The alarm's ScriptedAlarmId — equal to the materialised condition node's NodeId identifier
/// (T14 aligned the condition NodeId to the ScriptedAlarmId). The engine keys its domain state by
/// this id.
/// </param>
/// <param name="Operation">
/// The Part 9 operation, one of: <c>Acknowledge</c>, <c>Confirm</c>, <c>OneShotShelve</c>,
/// <c>TimedShelve</c>, <c>Unshelve</c>, <c>Enable</c>, <c>Disable</c>, <c>AddComment</c>. These map
/// 1:1 onto the engine's <c>Part9StateMachine.Apply*</c> calls on the consuming side (T19).
/// Note: <c>Enable</c> and <c>Disable</c> are part of the vocabulary but are not yet wired at the
/// node-manager seam (T18 wired Acknowledge/Confirm/AddComment/Shelve/TimedUnshelve only);
/// <c>OnEnableDisable</c> delegate wiring is a future task.
/// </param>
/// <param name="User">The acting user — the authenticated session identity's display/name.</param>
/// <param name="Comment">
/// The free-text comment supplied with the call (the OPC UA <c>LocalizedText</c> payload's text),
/// or <c>null</c> when none was provided.
/// </param>
/// <param name="UnshelveAtUtc">
/// For <c>TimedShelve</c>, the absolute UTC instant the shelve auto-expires
/// (<c>DateTime.UtcNow + shelvingTime</c>, where the OPC UA <c>Duration</c> <c>shelvingTime</c> is
/// in <b>milliseconds</b>); <c>null</c> for every other operation.
/// </param>
public sealed record AlarmCommand(
string AlarmId,
string Operation,
string User,
string? Comment,
DateTime? UnshelveAtUtc);