feat(uns): per-equipment tag/virtual-tag list service methods
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
||||||
|
|
||||||
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
||||||
|
|
||||||
|
/// <summary>A tag row for the equipment page's Tags tab table — display columns plus the id used to
|
||||||
|
/// open the edit modal. RowVersion is re-read fresh on delete (matching the tree's delete path).</summary>
|
||||||
|
public sealed record EquipmentTagRow(string TagId, string Name, string DriverInstanceId, string DataType, TagAccessLevel AccessLevel);
|
||||||
|
|
||||||
|
/// <summary>A virtual-tag row for the equipment page's Virtual Tags tab table.</summary>
|
||||||
|
public sealed record EquipmentVirtualTagRow(string VirtualTagId, string Name, string DataType, string ScriptId, bool Enabled);
|
||||||
@@ -127,6 +127,28 @@ public interface IUnsTreeService
|
|||||||
/// <returns>Tag nodes followed by VirtualTag nodes; empty if the equipment has none.</returns>
|
/// <returns>Tag nodes followed by VirtualTag nodes; empty if the equipment has none.</returns>
|
||||||
Task<IReadOnlyList<UnsNode>> LoadEquipmentChildrenAsync(string equipmentId, CancellationToken ct = default);
|
Task<IReadOnlyList<UnsNode>> LoadEquipmentChildrenAsync(string equipmentId, CancellationToken ct = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the driver tags bound to a single equipment as flat row projections for the equipment
|
||||||
|
/// page's Tags tab table, ordered by Name. Each row carries the display columns plus the
|
||||||
|
/// <c>TagId</c> the table uses to open the edit modal. Reads untracked. Returns an empty list when
|
||||||
|
/// the equipment has no tags.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="equipmentId">The equipment whose tags to load.</param>
|
||||||
|
/// <param name="ct">A token to cancel the load.</param>
|
||||||
|
/// <returns>The equipment's tag rows ordered by Name; empty if it has none.</returns>
|
||||||
|
Task<IReadOnlyList<EquipmentTagRow>> LoadTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the virtual tags scoped to a single equipment as flat row projections for the equipment
|
||||||
|
/// page's Virtual Tags tab table, ordered by Name. Each row carries the display columns plus the
|
||||||
|
/// <c>VirtualTagId</c> the table uses to open the edit modal. Reads untracked. Returns an empty list
|
||||||
|
/// when the equipment has no virtual tags.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="equipmentId">The equipment whose virtual tags to load.</param>
|
||||||
|
/// <param name="ct">A token to cancel the load.</param>
|
||||||
|
/// <returns>The equipment's virtual-tag rows ordered by Name; empty if it has none.</returns>
|
||||||
|
Task<IReadOnlyList<EquipmentVirtualTagRow>> LoadVirtualTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a single UNS area projected for editing, or <c>null</c> if it no longer exists.
|
/// Loads a single UNS area projected for editing, or <c>null</c> if it no longer exists.
|
||||||
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
||||||
|
|||||||
@@ -127,6 +127,28 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<IReadOnlyList<EquipmentTagRow>> LoadTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
||||||
|
return await db.Tags.AsNoTracking()
|
||||||
|
.Where(t => t.EquipmentId == equipmentId)
|
||||||
|
.OrderBy(t => t.Name)
|
||||||
|
.Select(t => new EquipmentTagRow(t.TagId, t.Name, t.DriverInstanceId, t.DataType, t.AccessLevel))
|
||||||
|
.ToListAsync(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<IReadOnlyList<EquipmentVirtualTagRow>> LoadVirtualTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
||||||
|
return await db.VirtualTags.AsNoTracking()
|
||||||
|
.Where(v => v.EquipmentId == equipmentId)
|
||||||
|
.OrderBy(v => v.Name)
|
||||||
|
.Select(v => new EquipmentVirtualTagRow(v.VirtualTagId, v.Name, v.DataType, v.ScriptId, v.Enabled))
|
||||||
|
.ToListAsync(ct);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<AreaEditDto?> LoadAreaAsync(string unsAreaId, CancellationToken ct = default)
|
public async Task<AreaEditDto?> LoadAreaAsync(string unsAreaId, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
|||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
using Shouldly;
|
||||||
|
using Xunit;
|
||||||
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
||||||
|
|
||||||
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
||||||
|
|
||||||
|
[Trait("Category", "Unit")]
|
||||||
|
public sealed class UnsTreeServiceEquipmentChildRowsTests
|
||||||
|
{
|
||||||
|
private static UnsTreeService SeededService()
|
||||||
|
{
|
||||||
|
var dbName = $"uns-childrows-{Guid.NewGuid():N}";
|
||||||
|
UnsTreeTestDb.SeedNamed(dbName);
|
||||||
|
return new UnsTreeService(UnsTreeTestDb.Factory(dbName));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task LoadTagsForEquipment_returns_tags_in_name_order_scoped()
|
||||||
|
{
|
||||||
|
var rows = await SeededService().LoadTagsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId);
|
||||||
|
rows.Count.ShouldBe(2); // the EquipmentId=null orphan tag is excluded
|
||||||
|
rows[0].TagId.ShouldBe("TAG-2"); // "running" < "speed"
|
||||||
|
rows[0].Name.ShouldBe("running");
|
||||||
|
rows[0].DataType.ShouldBe("Boolean");
|
||||||
|
rows[1].TagId.ShouldBe("TAG-1");
|
||||||
|
rows[1].DataType.ShouldBe("Float");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task LoadVirtualTagsForEquipment_returns_vtags_in_name_order()
|
||||||
|
{
|
||||||
|
var rows = await SeededService().LoadVirtualTagsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId);
|
||||||
|
rows.Count.ShouldBe(1);
|
||||||
|
rows[0].VirtualTagId.ShouldBe("VTAG-1");
|
||||||
|
rows[0].Name.ShouldBe("computed");
|
||||||
|
rows[0].DataType.ShouldBe("Double");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task LoadTagsForEquipment_empty_for_unknown_equipment()
|
||||||
|
=> (await SeededService().LoadTagsForEquipmentAsync("EQ-NONE")).ShouldBeEmpty();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user