feat(adminui): Galaxy picker pre-fills native-alarm fields from IsAlarm

This commit is contained in:
Joseph Doherty
2026-06-16 16:55:05 -04:00
parent 9a8b8ff6f6
commit 069a5f3165
6 changed files with 129 additions and 5 deletions
@@ -94,6 +94,41 @@ public sealed class NativeAlarmModel
/// <summary>Validation hook; returns an error message or null when the model is valid.</summary>
public string? Validate() => null;
/// <summary>Default <c>alarmType</c> seeded when an alarm-bearing attribute is picked but the
/// TagConfig has no <c>alarm</c> object yet. Galaxy's <c>AlarmExtension</c> is a boolean
/// off-normal condition, so <c>OffNormalAlarm</c> is the natural Part 9 subtype.</summary>
public const string DefaultSeedAlarmType = "OffNormalAlarm";
/// <summary>Default OPC UA severity (1..1000) seeded for a freshly pre-filled native alarm.</summary>
public const int DefaultSeedSeverity = 700;
/// <summary>
/// Pre-seeds a default native-alarm <c>alarm</c> object into <paramref name="json"/> when the
/// selected driver attribute is itself an alarm and the TagConfig carries no <c>alarm</c> object
/// yet. This is the Galaxy-picker convenience: picking an <c>IsAlarm</c> attribute materialises a
/// ready-to-author Part 9 condition (<c>{"alarmType":"OffNormalAlarm","severity":700}</c>) so the
/// operator doesn't hand-write the JSON. Every existing key (root + a pre-existing <c>alarm</c>) is
/// preserved: when an <c>alarm</c> object already exists this returns the input unchanged (never
/// overwrites an authored alarm). Returns the (possibly unchanged) TagConfig JSON string.
/// </summary>
public static string SeedDefaultAlarm(string? json)
{
var root = TagConfigJson.ParseOrNew(json);
// Never overwrite an existing alarm object (only seed when absent).
if (root.TryGetPropertyValue("alarm", out var existing) && existing is JsonObject)
{
return TagConfigJson.Serialize(root);
}
var alarm = new JsonObject();
TagConfigJson.Set(alarm, "alarmType", DefaultSeedAlarmType);
TagConfigJson.Set(alarm, "severity", DefaultSeedSeverity);
root["alarm"] = alarm;
return TagConfigJson.Serialize(root);
}
/// <summary>Reads a nullable bool: <c>null</c> when absent/null/non-bool; otherwise the bool value.</summary>
private static bool? ReadNullableBool(JsonObject o, string name)
=> o.TryGetPropertyValue(name, out var n) && n is JsonValue v && v.TryGetValue<bool>(out var b)