feat(client-ui): AlarmsViewModel Shelve/Confirm methods + CanShelve/CanConfirm

This commit is contained in:
Joseph Doherty
2026-06-16 18:23:11 -04:00
parent 8980adceb3
commit 4f55d894a2
3 changed files with 271 additions and 0 deletions
@@ -96,4 +96,10 @@ public class AlarmEventViewModel : ObservableObject
/// <summary>Whether this alarm can be acknowledged (active, not yet acked, has EventId).</summary>
public bool CanAcknowledge => ActiveState && !AckedState && EventId != null && ConditionNodeId != null;
/// <summary>Whether this alarm can be shelved/unshelved (has a ConditionNodeId).</summary>
public bool CanShelve => ConditionNodeId != null;
/// <summary>Whether this alarm can be confirmed (already acked, has EventId + ConditionNodeId).</summary>
public bool CanConfirm => AckedState && EventId != null && ConditionNodeId != null;
}
@@ -192,6 +192,54 @@ public partial class AlarmsViewModel : ObservableObject
}
}
/// <summary>Shelves / unshelves an alarm and returns (success, message).</summary>
/// <param name="alarm">The alarm event to shelve or unshelve.</param>
/// <param name="kind">The shelve operation (OneShot / Timed / Unshelve).</param>
/// <param name="durationSeconds">The timed-shelve duration in seconds (required for <see cref="ShelveKind.Timed"/>).</param>
/// <returns>A tuple with success flag and message.</returns>
public async Task<(bool Success, string Message)> ShelveAlarmAsync(
AlarmEventViewModel alarm, ShelveKind kind, double durationSeconds)
{
if (!IsConnected || alarm.ConditionNodeId == null)
return (false, "Alarm cannot be shelved (not connected or missing ConditionId).");
if (kind == ShelveKind.Timed && durationSeconds <= 0)
return (false, "Timed shelve requires a positive duration (seconds).");
try
{
var result = await _service.ShelveAlarmAsync(alarm.ConditionNodeId, kind, durationSeconds);
if (Opc.Ua.StatusCode.IsGood(result))
return (true, $"Alarm {kind.ToString().ToLowerInvariant()} succeeded.");
return (false, $"Shelve failed: {Helpers.StatusCodeFormatter.Format(result)}");
}
catch (Exception ex)
{
return (false, $"Error: {ex.Message}");
}
}
/// <summary>Confirms an alarm and returns (success, message).</summary>
/// <param name="alarm">The alarm event to confirm.</param>
/// <param name="comment">Optional comment for the confirmation.</param>
/// <returns>A tuple with success flag and message.</returns>
public async Task<(bool Success, string Message)> ConfirmAlarmAsync(AlarmEventViewModel alarm, string comment)
{
if (!IsConnected || alarm.EventId == null || alarm.ConditionNodeId == null)
return (false, "Alarm cannot be confirmed (missing EventId or ConditionId).");
try
{
var result = await _service.ConfirmAlarmAsync(alarm.ConditionNodeId, alarm.EventId, comment);
if (Opc.Ua.StatusCode.IsGood(result))
return (true, "Alarm confirmed successfully.");
return (false, $"Confirm failed: {Helpers.StatusCodeFormatter.Format(result)}");
}
catch (Exception ex)
{
return (false, $"Error: {ex.Message}");
}
}
/// <summary>
/// Returns the monitored node ID for persistence, or null if not subscribed.
/// </summary>