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.
This commit is contained in:
@@ -37,6 +37,38 @@ public sealed class AdminOperationsClient : IAdminOperationsClient
|
||||
return await _proxy.Ask<StartDeploymentResult>(msg, AskTimeout, linked.Token);
|
||||
}
|
||||
|
||||
/// <summary>Acknowledges one alarm via the admin singleton.</summary>
|
||||
/// <param name="alarmId">The alarm's ScriptedAlarmId.</param>
|
||||
/// <param name="user">The acting operator's name.</param>
|
||||
/// <param name="comment">Optional free-text comment; null when none.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <returns>The acknowledge result.</returns>
|
||||
public async Task<AcknowledgeAlarmResult> AcknowledgeAlarmAsync(
|
||||
string alarmId, string user, string? comment, CancellationToken ct)
|
||||
{
|
||||
var msg = new AcknowledgeAlarmCommand(alarmId, user, comment, Guid.NewGuid());
|
||||
using var linked = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
linked.CancelAfter(AskTimeout);
|
||||
return await _proxy.Ask<AcknowledgeAlarmResult>(msg, AskTimeout, linked.Token);
|
||||
}
|
||||
|
||||
/// <summary>Shelves or unshelves one alarm via the admin singleton.</summary>
|
||||
/// <param name="alarmId">The alarm's ScriptedAlarmId.</param>
|
||||
/// <param name="user">The acting operator's name.</param>
|
||||
/// <param name="kind">Which shelve action to perform.</param>
|
||||
/// <param name="unshelveAtUtc">For a timed shelve, when it expires; null otherwise.</param>
|
||||
/// <param name="comment">Optional free-text comment; null when none.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <returns>The shelve result.</returns>
|
||||
public async Task<ShelveAlarmResult> ShelveAlarmAsync(
|
||||
string alarmId, string user, ShelveKind kind, DateTime? unshelveAtUtc, string? comment, CancellationToken ct)
|
||||
{
|
||||
var msg = new ShelveAlarmCommand(alarmId, user, kind, unshelveAtUtc, comment, Guid.NewGuid());
|
||||
using var linked = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
||||
linked.CancelAfter(AskTimeout);
|
||||
return await _proxy.Ask<ShelveAlarmResult>(msg, AskTimeout, linked.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic Ask — forwards any message to the AdminOperationsActor singleton proxy.
|
||||
/// Uses the caller-supplied <paramref name="ct"/> for cancellation; does not impose an
|
||||
|
||||
Reference in New Issue
Block a user