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:
@@ -721,10 +721,9 @@ public static class InstanceCommands
|
||||
return 1;
|
||||
}
|
||||
|
||||
var overrides = parseResult.Rows
|
||||
.Select(r => new NativeAlarmSourceOverrideEntry(
|
||||
r.SourceName, r.Connection, r.SourceReference, r.Filter, r.MesReportable))
|
||||
.ToList();
|
||||
// A legacy 4-column file leaves the MES flag unspecified, so the server keeps the
|
||||
// stored overrides (ScadaBridge#104) — the same result as the Central UI import.
|
||||
var overrides = parseResult.Rows.Select(r => r.ToOverrideEntry()).ToList();
|
||||
return await CommandHelpers.ExecuteCommandAsync(
|
||||
result, urlOption, formatOption, usernameOption, passwordOption,
|
||||
new SetInstanceNativeAlarmSourceOverridesCommand(id, overrides));
|
||||
|
||||
@@ -648,8 +648,9 @@ Bulk-apply native alarm source overrides for a single instance from a CSV file
|
||||
(all-or-nothing — the native-source parity of `instance import-overrides`). The CSV
|
||||
header is required: `SourceName,Connection,SourceReference,Filter`, optionally followed by
|
||||
`MesReportable` (`true`, `false` or blank = inherit); a blank override field keeps the
|
||||
inherited value. Without the `MesReportable` column every imported source's MES override
|
||||
is reset to inherit, so include it to preserve or set MES-reportable overrides. Every named source must resolve for the instance and
|
||||
inherited value. Without the `MesReportable` column the file does not specify the MES flag and
|
||||
each source keeps its stored MES-reportable override (the same as the Central UI import); include
|
||||
the column to set or clear it. Every named source must resolve for the instance and
|
||||
be unlocked, or the whole batch is rejected before any write.
|
||||
|
||||
```sh
|
||||
|
||||
+1
-5
@@ -1885,11 +1885,7 @@
|
||||
}
|
||||
|
||||
await MutationServices.ExecuteConfigurationAsync(new SetInstanceNativeAlarmSourceOverridesCommand(Id,
|
||||
outcome.Rows.Select(row => new NativeAlarmSourceOverrideEntry(row.SourceName, row.Connection, row.SourceReference, row.Filter,
|
||||
// A file with the MesReportable column is authoritative; a legacy 4-column file keeps the stored flag.
|
||||
row.HasMesColumn
|
||||
? row.MesReportable
|
||||
: _existingNativeOverrides.GetValueOrDefault(row.SourceName)?.IsMesReportableOverride)).ToList()));
|
||||
outcome.Rows.Select(row => row.ToOverrideEntry()).ToList()));
|
||||
await OnInitializedAsync();
|
||||
|
||||
_nasCsvImportSucceeded = true;
|
||||
|
||||
+10
@@ -1,4 +1,5 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||
|
||||
@@ -143,6 +144,15 @@ public partial class InstanceConfigure
|
||||
{
|
||||
/// <summary>True when all three override fields are blank (row means "inherit everything").</summary>
|
||||
public bool IsClear => Connection is null && SourceReference is null && Filter is null;
|
||||
|
||||
/// <summary>
|
||||
/// The bulk-apply entry for this row. A file with the <c>MesReportable</c> column is
|
||||
/// authoritative for the flag; a legacy 4-column file leaves it unspecified, so the server
|
||||
/// keeps the stored value (ScadaBridge#104) — the same entry the CLI import sends.
|
||||
/// </summary>
|
||||
/// <returns>The entry for <c>SetInstanceNativeAlarmSourceOverridesCommand</c>.</returns>
|
||||
public NativeAlarmSourceOverrideEntry ToOverrideEntry() =>
|
||||
new(SourceName, Connection, SourceReference, Filter, MesReportable, KeepStoredMesReportable: !HasMesColumn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,17 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||
/// </remarks>
|
||||
public sealed record NativeAlarmSourceOverrideCsvRow(
|
||||
string SourceName, string? Connection, string? SourceReference, string? Filter, int LineNumber,
|
||||
bool? MesReportable = null, bool HasMesColumn = false);
|
||||
bool? MesReportable = null, bool HasMesColumn = false)
|
||||
{
|
||||
/// <summary>
|
||||
/// The bulk-apply entry for this row. Without the <c>MesReportable</c> column the entry
|
||||
/// leaves the MES flag unspecified, so the server keeps each source's stored override
|
||||
/// instead of resetting it to inherit (ScadaBridge#104).
|
||||
/// </summary>
|
||||
/// <returns>The entry for <c>SetInstanceNativeAlarmSourceOverridesCommand</c>.</returns>
|
||||
public ZB.MOM.WW.ScadaBridge.Commons.Messages.Management.NativeAlarmSourceOverrideEntry ToOverrideEntry() =>
|
||||
new(SourceName, Connection, SourceReference, Filter, MesReportable, KeepStoredMesReportable: !HasMesColumn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outcome of parsing a native-alarm-source-override CSV: the successfully-parsed
|
||||
|
||||
@@ -1371,7 +1371,9 @@ public class ManagementActor : ReceiveActor
|
||||
ConnectionNameOverride = entry.ConnectionNameOverride,
|
||||
SourceReferenceOverride = entry.SourceReferenceOverride,
|
||||
ConditionFilterOverride = entry.ConditionFilterOverride,
|
||||
IsMesReportableOverride = entry.IsMesReportableOverride
|
||||
// ScadaBridge#104: an entry that leaves the MES flag unspecified keeps the
|
||||
// stored value — for a new row that is "inherit".
|
||||
IsMesReportableOverride = entry.KeepStoredMesReportable ? null : entry.IsMesReportableOverride
|
||||
};
|
||||
await repo.AddInstanceNativeAlarmSourceOverrideAsync(ovr);
|
||||
results.Add(ovr);
|
||||
@@ -1381,7 +1383,8 @@ public class ManagementActor : ReceiveActor
|
||||
existing.ConnectionNameOverride = entry.ConnectionNameOverride;
|
||||
existing.SourceReferenceOverride = entry.SourceReferenceOverride;
|
||||
existing.ConditionFilterOverride = entry.ConditionFilterOverride;
|
||||
existing.IsMesReportableOverride = entry.IsMesReportableOverride;
|
||||
if (!entry.KeepStoredMesReportable)
|
||||
existing.IsMesReportableOverride = entry.IsMesReportableOverride;
|
||||
await repo.UpdateInstanceNativeAlarmSourceOverrideAsync(existing);
|
||||
results.Add(existing);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user