fix(native-alarms): a 4-column CSV import keeps stored MES overrides on the CLI path too (ScadaBridge#104)

The bulk SetInstanceNativeAlarmSourceOverridesCommand handler always wrote the
entry's IsMesReportableOverride, so a CLI import of a legacy 4-column CSV (no
MesReportable column) reset every imported source's MES override to inherit. The
Central UI avoided it only by looking up the stored flag client-side.

NativeAlarmSourceOverrideEntry gains an additive trailing KeepStoredMesReportable
flag: when set, the server leaves an existing row's MES override untouched (a new
row inherits) and ignores IsMesReportableOverride; unset keeps the old meaning
(null = clear to inherit), so older senders are unaffected. The CLI and the Central
UI now build their entries through one rule (ToOverrideEntry on each row type):
no MesReportable column => KeepStoredMesReportable. CLI README and
Component-CentralUI updated.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 15:41:33 -05:00
parent a81dac76ed
commit 063fb21815
11 changed files with 197 additions and 16 deletions
@@ -80,12 +80,28 @@ public record ListInstanceNativeAlarmSourceOverridesCommand(int InstanceId);
/// value). Mirrors <see cref="SetInstanceNativeAlarmSourceOverrideCommand"/>'s fields
/// for a single source.
/// </summary>
/// <remarks>
/// <see cref="IsMesReportableOverride"/> is written as given — <c>null</c> means "inherit the
/// binding's flag" and clears a stored override — unless <see cref="KeepStoredMesReportable"/>
/// is set (ScadaBridge#104). Then the entry does not specify the MES flag at all: the server
/// keeps the instance's stored <c>IsMesReportableOverride</c> (inherit for a new override row)
/// and ignores <see cref="IsMesReportableOverride"/>. The CLI and Central UI CSV imports set it
/// for a legacy 4-column file that has no <c>MesReportable</c> column, so importing such a file
/// never resets MES overrides. Additive trailing optional: older senders keep the old meaning.
/// </remarks>
/// <param name="SourceCanonicalName">The native alarm source's canonical name.</param>
/// <param name="ConnectionNameOverride">Connection retarget, or null to inherit.</param>
/// <param name="SourceReferenceOverride">Source-reference retarget, or null to inherit.</param>
/// <param name="ConditionFilterOverride">Condition-filter retarget, or null to inherit.</param>
/// <param name="IsMesReportableOverride">MES-reportable override, or null to inherit.</param>
/// <param name="KeepStoredMesReportable">True when the entry leaves the MES flag unspecified.</param>
public record NativeAlarmSourceOverrideEntry(
string SourceCanonicalName,
string? ConnectionNameOverride,
string? SourceReferenceOverride,
string? ConditionFilterOverride,
bool? IsMesReportableOverride = null);
bool? IsMesReportableOverride = null,
bool KeepStoredMesReportable = false);
/// <summary>
/// Bulk, all-or-nothing apply of per-instance native-alarm-source overrides — the