feat(uns): per-equipment tag/virtual-tag list service methods

This commit is contained in:
Joseph Doherty
2026-06-11 14:19:46 -04:00
parent 7d91737dac
commit 7c22861598
4 changed files with 96 additions and 0 deletions
@@ -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>
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>
/// 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.
@@ -127,6 +127,28 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
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 />
public async Task<AreaEditDto?> LoadAreaAsync(string unsAreaId, CancellationToken ct = default)
{