fix(adminui): canonicalize Modbus driver-type string on "Modbus" (was ModbusTcp)

This commit is contained in:
Joseph Doherty
2026-06-16 19:39:41 -04:00
parent 3fcbc70cba
commit 8b4675b1a5
15 changed files with 28 additions and 23 deletions
@@ -26,7 +26,7 @@ public sealed class ModbusDriverProbe : IDriverProbe
private static readonly byte[] Fc03Pdu = [0x03, 0x00, 0x00, 0x00, 0x01];
/// <inheritdoc />
public string DriverType => "ModbusTcp";
public string DriverType => "Modbus";
/// <inheritdoc />
public async Task<DriverProbeResult> ProbeAsync(string configJson, TimeSpan timeout, CancellationToken ct)
@@ -52,7 +52,7 @@ else
private static readonly IReadOnlyDictionary<string, Type> _componentMap =
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
{
["ModbusTcp"] = typeof(ModbusDriverPage),
["Modbus"] = typeof(ModbusDriverPage),
["AbCip"] = typeof(AbCipDriverPage),
["AbLegacy"] = typeof(AbLegacyDriverPage),
["S7"] = typeof(S7DriverPage),
@@ -37,7 +37,7 @@
private static readonly IReadOnlyList<DriverTypeEntry> _types = new[]
{
new DriverTypeEntry("ModbusTcp", "modbustcp", "[M]", "Modbus/TCP — generic registers/coils via port 502."),
new DriverTypeEntry("Modbus TCP", "modbustcp", "[M]", "Modbus/TCP — generic registers/coils via port 502."),
new DriverTypeEntry("AbCip", "abcip", "[CIP]", "Allen-Bradley CompactLogix/ControlLogix via CIP."),
new DriverTypeEntry("AbLegacy", "ablegacy", "[AB]", "Allen-Bradley PLC-5/SLC-500/MicroLogix via DF1."),
new DriverTypeEntry("S7", "s7", "[S7]", "Siemens S7-300/400/1200/1500 via ISO-on-TCP."),
@@ -321,7 +321,7 @@ else
[Parameter] public string ClusterId { get; set; } = "";
[Parameter] public string? DriverInstanceId { get; set; }
private const string DriverTypeKey = "ModbusTcp";
private const string DriverTypeKey = "Modbus";
private bool IsNew => string.IsNullOrEmpty(DriverInstanceId);
@@ -28,7 +28,7 @@
<label class="form-label" for="dtype">Driver type</label>
<InputSelect id="dtype" @bind-Value="Model.DriverType" disabled="@(!IsNew)"
class="form-select form-select-sm">
<option value="ModbusTcp">ModbusTcp</option>
<option value="Modbus">Modbus TCP</option>
<option value="AbCip">AbCip</option>
<option value="AbLegacy">AbLegacy</option>
<option value="S7">S7</option>
@@ -73,7 +73,7 @@
[Required, RegularExpression("^[A-Za-z0-9_-]+$", ErrorMessage = "Use letters, digits, dash, underscore.")]
public string DriverInstanceId { get; set; } = "";
[Required] public string Name { get; set; } = "";
[Required] public string DriverType { get; set; } = "ModbusTcp";
[Required] public string DriverType { get; set; } = "Modbus";
[Required] public string NamespaceId { get; set; } = "";
public bool Enabled { get; set; } = true;
}
@@ -10,7 +10,7 @@ public static class TagConfigEditorMap
private static readonly IReadOnlyDictionary<string, Type> Map =
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase)
{
["ModbusTcp"] = typeof(Components.Shared.Uns.TagEditors.ModbusTagConfigEditor),
["Modbus"] = typeof(Components.Shared.Uns.TagEditors.ModbusTagConfigEditor),
["S7"] = typeof(Components.Shared.Uns.TagEditors.S7TagConfigEditor),
["AbCip"] = typeof(Components.Shared.Uns.TagEditors.AbCipTagConfigEditor),
["AbLegacy"] = typeof(Components.Shared.Uns.TagEditors.AbLegacyTagConfigEditor),
@@ -12,7 +12,7 @@ public static class TagConfigValidator
private static readonly IReadOnlyDictionary<string, Func<string?, string?>> Validators =
new Dictionary<string, Func<string?, string?>>(StringComparer.OrdinalIgnoreCase)
{
["ModbusTcp"] = j => ModbusTagConfigModel.FromJson(j).Validate(),
["Modbus"] = j => ModbusTagConfigModel.FromJson(j).Validate(),
["S7"] = j => S7TagConfigModel.FromJson(j).Validate(),
["AbCip"] = j => AbCipTagConfigModel.FromJson(j).Validate(),
["AbLegacy"] = j => AbLegacyTagConfigModel.FromJson(j).Validate(),
@@ -16,7 +16,12 @@ public sealed class TagConfigValidatorTests
[Fact]
public void Modbus_has_no_required_field_so_empty_config_is_valid()
=> TagConfigValidator.Validate("ModbusTcp", "{}").ShouldBeNull();
=> TagConfigValidator.Validate("Modbus", "{}").ShouldBeNull();
[Fact]
public void Resolve_Modbus_dispatches_typed_editor()
=> TagConfigEditorMap.Resolve("Modbus")
.ShouldBe(typeof(ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Uns.TagEditors.ModbusTagConfigEditor));
// Drivers whose Validate() requires a field: blank config must return an error string.
[Theory]
@@ -114,7 +114,7 @@ public sealed class UnsTreeServiceAreaLineTests
ClusterId = "MAIN",
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.SaveChanges();
@@ -156,7 +156,7 @@ public sealed class UnsTreeServiceAreaLineTests
ClusterId = "SITE-A",
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.Equipment.Add(new Equipment
@@ -358,7 +358,7 @@ public sealed class UnsTreeServiceAreaLineTests
ClusterId = "MAIN",
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.Equipment.Add(new Equipment
@@ -107,7 +107,7 @@ public sealed class UnsTreeServiceDeleteClusterTests
ClusterId = "CL-DRV",
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.SaveChanges();
@@ -43,7 +43,7 @@ public sealed class UnsTreeServiceEquipmentTests
ClusterId = driverCluster,
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
}
@@ -174,7 +174,7 @@ public sealed class UnsTreeServiceEquipmentTests
ClusterId = "MAIN",
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.SaveChanges();
@@ -38,7 +38,7 @@ public sealed class UnsTreeServiceImportTests
ClusterId = driverCluster,
NamespaceId = "NS-1",
Name = "drv",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
}
@@ -110,7 +110,7 @@ public sealed class UnsTreeServiceLoadEditTests
ClusterId = UnsTreeTestDb.PopulatedClusterId,
NamespaceId = "NS-1",
Name = "modbus-b",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
db.DriverInstances.Add(new DriverInstance
@@ -141,7 +141,7 @@ public sealed class UnsTreeServiceLoadEditTests
drivers[0].DriverInstanceId.ShouldBe("DRV-A");
drivers[0].Display.ShouldBe("DRV-A — galaxy-a (Galaxy)");
drivers[1].DriverInstanceId.ShouldBe("DRV-B");
drivers[1].Display.ShouldBe("DRV-B — modbus-b (ModbusTcp)");
drivers[1].Display.ShouldBe("DRV-B — modbus-b (Modbus)");
}
/// <summary>Loading a seeded tag maps its fields, owning equipment, and a non-empty RowVersion.</summary>
@@ -58,7 +58,7 @@ public sealed class UnsTreeServiceTagDriversTests
ClusterId = "MAIN",
NamespaceId = "NS-EQ",
Name = "equipment driver",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = """{"endpoint":"10.0.0.1:502"}""",
});
db.SaveChanges();
@@ -70,7 +70,7 @@ public sealed class UnsTreeServiceTagDriversTests
drivers.Count.ShouldBe(1);
drivers[0].DriverInstanceId.ShouldBe("DRV-EQ");
drivers[0].DriverType.ShouldBe("ModbusTcp");
drivers[0].DriverType.ShouldBe("Modbus");
// The picker (Galaxy live-browse) opens its session against the selected driver's config.
drivers[0].DriverConfig.ShouldBe("""{"endpoint":"10.0.0.1:502"}""");
}
@@ -76,7 +76,7 @@ public sealed class UnsTreeServiceTagTests
ClusterId = equipmentCluster,
NamespaceId = "NS-EQ",
Name = "equipment driver",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
}
@@ -89,7 +89,7 @@ public sealed class UnsTreeServiceTagTests
ClusterId = equipmentCluster,
NamespaceId = "NS-SP",
Name = "non-equipment driver",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
}
@@ -110,7 +110,7 @@ public sealed class UnsTreeServiceTagTests
ClusterId = otherCluster,
NamespaceId = "NS-OTHER",
Name = "other-cluster driver",
DriverType = "ModbusTcp",
DriverType = "Modbus",
DriverConfig = "{}",
});
}