diff --git a/docs/ScriptedAlarms.md b/docs/ScriptedAlarms.md index ea07808c..1155cd63 100644 --- a/docs/ScriptedAlarms.md +++ b/docs/ScriptedAlarms.md @@ -4,6 +4,10 @@ This file covers the engine internals — predicate evaluation, state machine, persistence, and the engine-to-`IAlarmSource` adapter. The server-side plumbing that turns those emissions into OPC UA `AlarmConditionState` nodes, applies retries, persists alarm transitions to the Historian, and routes operator acks through the session's `AlarmAck` permission lives in [AlarmTracking.md](AlarmTracking.md) and is not repeated here. +## Authoring (AdminUI) + +Scripted-alarm definitions are created and edited per-equipment on the **`/uns/equipment/{id}`** page's **Alarms** tab; the standalone `/scripted-alarms` management pages were retired in favour of this equipment-scoped surface. The **`/alerts`** page remains the live runtime view — it is where operators acknowledge, confirm, and shelve active alarm instances. + ## Definition shape `ScriptedAlarmDefinition` (`src/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms/ScriptedAlarmDefinition.cs`) is the runtime contract the engine consumes. The generation-publish path materialises these from the `ScriptedAlarm` + `Script` config tables via `Phase7Composer.Compose` + the driver-role host actor startup path. diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/EquipmentPage.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/EquipmentPage.razor index 64e34f5d..19d7d848 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/EquipmentPage.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/EquipmentPage.razor @@ -559,6 +559,7 @@ else if (IsNew) { // Redirect to the persisted editor so the other tabs (disabled while new) become available. + if (string.IsNullOrEmpty(result.CreatedId)) { _error = "Equipment was created but no id was returned."; return; } Nav.NavigateTo($"/uns/equipment/{result.CreatedId}"); } else diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceScriptedAlarmTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceScriptedAlarmTests.cs index e3c497ab..92ab0aab 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceScriptedAlarmTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceScriptedAlarmTests.cs @@ -86,4 +86,17 @@ public sealed class UnsTreeServiceScriptedAlarmTests dup.Error.ShouldNotBeNull(); dup.Error!.ShouldContain("already exists"); } + + [Fact] + public async Task LoadAlarmsForEquipment_excludes_other_equipment() + { + var svc = SeededService(); + await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-MINE")); + await svc.CreateScriptedAlarmAsync("EQ-OTHER", Sample("SA-OTHER") with { Name = "Other-alarm" }); + + var rows = await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId); + + rows.Count.ShouldBe(1); + rows[0].ScriptedAlarmId.ShouldBe("SA-MINE"); + } }