diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/GlobalUns.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/GlobalUns.razor
index 666bc43a..2ca36cf3 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/GlobalUns.razor
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Uns/GlobalUns.razor
@@ -157,7 +157,7 @@
private bool _tagModalIsNew;
private string? _tagModalEquipmentId;
private TagEditDto? _tagModalExisting;
- private IReadOnlyList<(string Id, string Display)> _tagModalDriverOptions = Array.Empty<(string, string)>();
+ private IReadOnlyList<(string Id, string Display, string DriverType)> _tagModalDriverOptions = Array.Empty<(string, string, string)>();
// --- Virtual-tag modal state ---
private bool _vtagModalVisible;
@@ -613,7 +613,7 @@
_tagModalIsNew = false;
_tagModalEquipmentId = null;
_tagModalExisting = null;
- _tagModalDriverOptions = Array.Empty<(string, string)>();
+ _tagModalDriverOptions = Array.Empty<(string, string, string)>();
_vtagModalVisible = false;
_vtagModalIsNew = false;
_vtagModalEquipmentId = null;
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor
index c9c9d701..78a66422 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor
@@ -43,7 +43,7 @@
- @foreach (var (id, display) in Drivers)
+ @foreach (var (id, display, _) in Drivers)
{
}
@@ -125,7 +125,7 @@
[Parameter] public TagEditDto? Existing { get; set; }
/// The candidate drivers — scoped to the equipment's cluster by the host — as (Id, Display) pairs.
- [Parameter] public IReadOnlyList<(string Id, string Display)> Drivers { get; set; } = Array.Empty<(string, string)>();
+ [Parameter] public IReadOnlyList<(string Id, string Display, string DriverType)> Drivers { get; set; } = Array.Empty<(string, string, string)>();
/// Raised after a successful create/save so the host can refresh the equipment's children and close.
[Parameter] public EventCallback OnSaved { get; set; }
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IUnsTreeService.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IUnsTreeService.cs
index d6361d21..d2151e86 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IUnsTreeService.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/IUnsTreeService.cs
@@ -316,8 +316,9 @@ public interface IUnsTreeService
///
/// The equipment whose candidate drivers to load.
/// A token to cancel the load.
- /// The eligible drivers projected to (DriverInstanceId, Display) pairs.
- Task> LoadTagDriversForEquipmentAsync(string equipmentId, CancellationToken ct = default);
+ /// The eligible drivers projected to (DriverInstanceId, Display, DriverType) triples,
+ /// where DriverType lets the TagModal dispatch to a per-driver-type typed config editor.
+ Task> LoadTagDriversForEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Creates a new equipment-bound tag. FolderPath is always null (decision #110 —
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsTreeService.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsTreeService.cs
index c50209ad..55bf08e0 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsTreeService.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsTreeService.cs
@@ -704,7 +704,7 @@ public sealed class UnsTreeService(IDbContextFactory dbF
}
///
- public async Task> LoadTagDriversForEquipmentAsync(
+ public async Task> LoadTagDriversForEquipmentAsync(
string equipmentId,
CancellationToken ct = default)
{
@@ -713,7 +713,7 @@ public sealed class UnsTreeService(IDbContextFactory dbF
var equipmentCluster = await ResolveEquipmentClusterAsync(db, equipmentId, ct);
if (equipmentCluster is null)
{
- return Array.Empty<(string, string)>();
+ return Array.Empty<(string, string, string)>();
}
// Drivers in the equipment's cluster whose namespace is Equipment-kind (decision #110).
@@ -725,11 +725,11 @@ public sealed class UnsTreeService(IDbContextFactory dbF
var drivers = await db.DriverInstances
.Where(d => d.ClusterId == equipmentCluster && equipmentNamespaceIds.Contains(d.NamespaceId))
.OrderBy(d => d.DriverInstanceId)
- .Select(d => new { d.DriverInstanceId, d.Name })
+ .Select(d => new { d.DriverInstanceId, d.Name, d.DriverType })
.ToListAsync(ct);
return drivers
- .Select(d => (d.DriverInstanceId, Display: $"{d.DriverInstanceId} — {d.Name}"))
+ .Select(d => (d.DriverInstanceId, Display: $"{d.DriverInstanceId} — {d.Name}", d.DriverType))
.ToList();
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagDriversTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagDriversTests.cs
new file mode 100644
index 00000000..11976c3d
--- /dev/null
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceTagDriversTests.cs
@@ -0,0 +1,73 @@
+using Shouldly;
+using Xunit;
+using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
+using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
+using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
+
+namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
+
+///
+/// Verifies that surfaces each
+/// candidate driver's DriverType alongside its id and display string, so the UNS TagModal
+/// can later dispatch to a per-driver-type typed tag-config editor (F-uns-1).
+///
+[Trait("Category", "Unit")]
+public sealed class UnsTreeServiceTagDriversTests
+{
+ ///
+ /// A driver loaded for an equipment carries its DriverType in the returned tuple.
+ ///
+ [Fact]
+ public async Task LoadTagDriversForEquipment_surfaces_driver_type()
+ {
+ var dbName = $"uns-tagdrivers-{Guid.NewGuid():N}";
+
+ using (var db = UnsTreeTestDb.CreateNamed(dbName))
+ {
+ db.ServerClusters.Add(new ServerCluster
+ {
+ ClusterId = "MAIN",
+ Name = "Main",
+ Enterprise = "zb",
+ Site = "warsaw-west",
+ RedundancyMode = RedundancyMode.None,
+ CreatedBy = "test",
+ });
+ db.UnsAreas.Add(new UnsArea { UnsAreaId = "AREA-1", ClusterId = "MAIN", Name = "a" });
+ db.UnsLines.Add(new UnsLine { UnsLineId = "LINE-1", UnsAreaId = "AREA-1", Name = "l" });
+ db.Equipment.Add(new Equipment
+ {
+ EquipmentId = "EQ-1",
+ EquipmentUuid = Guid.NewGuid(),
+ UnsLineId = "LINE-1",
+ Name = "machine-1",
+ MachineCode = "machine_001",
+ });
+ db.Namespaces.Add(new Namespace
+ {
+ NamespaceId = "NS-EQ",
+ ClusterId = "MAIN",
+ Kind = NamespaceKind.Equipment,
+ NamespaceUri = "urn:zb:eq",
+ });
+ db.DriverInstances.Add(new DriverInstance
+ {
+ DriverInstanceId = "DRV-EQ",
+ ClusterId = "MAIN",
+ NamespaceId = "NS-EQ",
+ Name = "equipment driver",
+ DriverType = "ModbusTcp",
+ DriverConfig = "{}",
+ });
+ db.SaveChanges();
+ }
+
+ var service = new UnsTreeService(UnsTreeTestDb.Factory(dbName));
+
+ var drivers = await service.LoadTagDriversForEquipmentAsync("EQ-1");
+
+ drivers.Count.ShouldBe(1);
+ drivers[0].DriverInstanceId.ShouldBe("DRV-EQ");
+ drivers[0].DriverType.ShouldBe("ModbusTcp");
+ }
+}