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 2ca36cf3..a026185a 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
@@ -4,6 +4,7 @@
@using ZB.MOM.WW.OtOpcUa.AdminUI.Uns
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Uns
@inject IUnsTreeService Svc
+@inject NavigationManager Nav
UNS
@@ -41,7 +42,6 @@
@@ -64,31 +64,6 @@
OnSaved="OnModalSavedAsync"
OnCancel="CloseModals" />
-
-
-
-
-
-
@@ -127,7 +102,7 @@
private string? _filter;
private bool _loading = true;
- // Guards the async modal openers (HandleAddChild/HandleAddVirtualTag/HandleEdit) so a rapid
+ // Guards the async modal openers (HandleAddChild/HandleEdit) so a rapid
// double-action can't race two service loads into the same modal state.
private bool _modalBusy;
@@ -144,34 +119,9 @@
private LineEditDto? _lineModalExisting;
private IReadOnlyList<(string Id, string Display)> _lineModalAreaOptions = Array.Empty<(string, string)>();
- // --- Equipment modal state ---
- private bool _equipmentModalVisible;
- private bool _equipmentModalIsNew;
- private string? _equipmentModalLineId;
- private EquipmentEditDto? _equipmentModalExisting;
- private IReadOnlyList<(string Id, string Display)> _equipmentModalLineOptions = Array.Empty<(string, string)>();
- private IReadOnlyList<(string Id, string Display)> _equipmentModalDriverOptions = Array.Empty<(string, string)>();
-
- // --- Tag modal state ---
- private bool _tagModalVisible;
- private bool _tagModalIsNew;
- private string? _tagModalEquipmentId;
- private TagEditDto? _tagModalExisting;
- private IReadOnlyList<(string Id, string Display, string DriverType)> _tagModalDriverOptions = Array.Empty<(string, string, string)>();
-
- // --- Virtual-tag modal state ---
- private bool _vtagModalVisible;
- private bool _vtagModalIsNew;
- private string? _vtagModalEquipmentId;
- private VirtualTagEditDto? _vtagModalExisting;
- private IReadOnlyList<(string Id, string Display)> _vtagModalScriptOptions = Array.Empty<(string, string)>();
-
// --- Import-equipment-CSV modal state ---
private bool _importModalVisible;
- // --- Owning equipment to refresh in place after a tag/virtual-tag mutation ---
- private string? _childRefreshEquipmentId;
-
// --- Delete-confirm state ---
private UnsNode? _confirmNode;
private bool _confirmBusy;
@@ -214,43 +164,21 @@
.ToList();
///
- /// Toggles a node's expansion. For equipment nodes whose children have not yet
- /// been loaded, lazily fetches the tag/virtual-tag leaves on first expand.
+ /// Toggles a structural node's expansion. Equipment nodes are leaves (no expander),
+ /// so this path only ever fires for Enterprise/Cluster/Area/Line.
///
- private async Task ToggleAsync(UnsNode node)
+ private Task ToggleAsync(UnsNode node)
{
- if (node.Loading) return;
+ if (node.Loading) { return Task.CompletedTask; }
node.Expanded = !node.Expanded;
-
- if (node.Kind == UnsNodeKind.Equipment && node.Expanded && !node.Loaded)
- {
- node.Error = null;
- node.Loading = true;
- StateHasChanged();
- try
- {
- var kids = await Svc.LoadEquipmentChildrenAsync(node.EntityId!);
- node.Children.Clear();
- node.Children.AddRange(kids);
- node.Loaded = true;
- }
- catch (Exception ex)
- {
- node.Error = ex.Message;
- }
- finally
- {
- node.Loading = false;
- StateHasChanged();
- }
- }
+ return Task.CompletedTask;
}
///
- /// Opens the create modal for a node's primary child: a cluster gets a new area; an area gets a
- /// new line scoped to its cluster; a line gets a new equipment scoped to its cluster; an equipment
- /// gets a new tag scoped to its candidate drivers.
+ /// Opens the create modal for a structural node's primary child: a cluster gets a new area; an area
+ /// gets a new line scoped to its cluster. A line's "+ Equipment" navigates to the equipment detail
+ /// page in create mode rather than opening a modal.
///
private async Task HandleAddChild(UnsNode node)
{
@@ -277,21 +205,7 @@
break;
case UnsNodeKind.Line:
- _equipmentModalIsNew = true;
- _equipmentModalExisting = null;
- _equipmentModalLineId = node.EntityId;
- _equipmentModalLineOptions = LinesForCluster(node.ClusterId);
- _equipmentModalDriverOptions = await Svc.LoadDriversForClusterAsync(node.ClusterId!);
- _equipmentModalVisible = true;
- break;
-
- case UnsNodeKind.Equipment:
- _tagModalIsNew = true;
- _tagModalExisting = null;
- _tagModalEquipmentId = node.EntityId;
- _childRefreshEquipmentId = node.EntityId;
- _tagModalDriverOptions = await Svc.LoadTagDriversForEquipmentAsync(node.EntityId!);
- _tagModalVisible = true;
+ Nav.NavigateTo($"/uns/equipment/new?lineId={node.EntityId}");
break;
}
}
@@ -301,31 +215,10 @@
}
}
- /// Opens the create modal for a new virtual tag scoped to the clicked equipment.
- private async Task HandleAddVirtualTag(UnsNode node)
- {
- if (_modalBusy) { return; }
- _modalBusy = true;
- try
- {
- CloseModals();
- _vtagModalIsNew = true;
- _vtagModalExisting = null;
- _vtagModalEquipmentId = node.EntityId;
- _childRefreshEquipmentId = node.EntityId;
- _vtagModalScriptOptions = await Svc.LoadScriptsAsync();
- _vtagModalVisible = true;
- }
- finally
- {
- _modalBusy = false;
- }
- }
-
///
/// Opens the edit modal for the clicked node, loading the entity first to prefill the form and
- /// capture its RowVersion. Tag/VirtualTag edits also stash the owning equipment id so a successful
- /// save can refresh just that equipment's children in place.
+ /// capture its RowVersion. Only Area and Line are edited via a modal here; equipment is edited on
+ /// its own detail page (opened via the tree's "Open" link).
///
private async Task HandleEdit(UnsNode node)
{
@@ -354,39 +247,6 @@
_lineModalAreaOptions = AreaOptionsForCluster(node.ClusterId);
_lineModalVisible = true;
break;
-
- case UnsNodeKind.Equipment:
- var equipment = await Svc.LoadEquipmentAsync(node.EntityId!);
- if (equipment is null) { return; }
- _equipmentModalIsNew = false;
- _equipmentModalExisting = equipment;
- _equipmentModalLineId = equipment.UnsLineId;
- _equipmentModalLineOptions = LinesForCluster(node.ClusterId);
- _equipmentModalDriverOptions = await Svc.LoadDriversForClusterAsync(node.ClusterId!);
- _equipmentModalVisible = true;
- break;
-
- case UnsNodeKind.Tag:
- var tag = await Svc.LoadTagAsync(node.EntityId!);
- if (tag is null) { return; }
- _tagModalIsNew = false;
- _tagModalExisting = tag;
- _tagModalEquipmentId = tag.EquipmentId;
- _childRefreshEquipmentId = tag.EquipmentId;
- _tagModalDriverOptions = await Svc.LoadTagDriversForEquipmentAsync(tag.EquipmentId);
- _tagModalVisible = true;
- break;
-
- case UnsNodeKind.VirtualTag:
- var vtag = await Svc.LoadVirtualTagAsync(node.EntityId!);
- if (vtag is null) { return; }
- _vtagModalIsNew = false;
- _vtagModalExisting = vtag;
- _vtagModalEquipmentId = vtag.EquipmentId;
- _childRefreshEquipmentId = vtag.EquipmentId;
- _vtagModalScriptOptions = await Svc.LoadScriptsAsync();
- _vtagModalVisible = true;
- break;
}
}
finally
@@ -422,8 +282,7 @@
///
/// Performs the pending delete. Loads the entity's RowVersion first, then dispatches on Kind.
- /// Area/Line/Equipment trigger a full structural reload on success; Tag/VirtualTag refresh only the
- /// owning equipment's children in place so the rest of the user's expansion is preserved.
+ /// Area/Line/Equipment trigger a full structural reload on success.
///
private async Task ConfirmDeleteAsync()
{
@@ -436,42 +295,8 @@
var node = _confirmNode;
UnsMutationResult result;
- // Tag/VirtualTag deletes refresh just the owning equipment's children rather than the
- // whole tree, so they're handled separately from the structural Area/Line/Equipment path.
switch (node.Kind)
{
- case UnsNodeKind.Tag:
- var tag = await Svc.LoadTagAsync(node.EntityId!);
- if (tag is null) { await ReloadAndCloseAsync(); return; }
- result = await Svc.DeleteTagAsync(node.EntityId!, tag.RowVersion);
- if (result.Ok)
- {
- await RefreshEquipmentChildrenAsync(tag.EquipmentId);
- CloseModals();
- StateHasChanged();
- }
- else
- {
- _confirmError = result.Error;
- }
- return;
-
- case UnsNodeKind.VirtualTag:
- var vtag = await Svc.LoadVirtualTagAsync(node.EntityId!);
- if (vtag is null) { await ReloadAndCloseAsync(); return; }
- result = await Svc.DeleteVirtualTagAsync(node.EntityId!, vtag.RowVersion);
- if (result.Ok)
- {
- await RefreshEquipmentChildrenAsync(vtag.EquipmentId);
- CloseModals();
- StateHasChanged();
- }
- else
- {
- _confirmError = result.Error;
- }
- return;
-
case UnsNodeKind.Area:
var area = await Svc.LoadAreaAsync(node.EntityId!);
if (area is null) { await ReloadAndCloseAsync(); return; }
@@ -519,70 +344,6 @@
StateHasChanged();
}
- ///
- /// Handles a successful Tag/VirtualTag modal save by refreshing only the owning equipment's children
- /// in place — never a full structural reload, which would collapse the user's expansion.
- ///
- private async Task OnEquipmentChildModalSavedAsync()
- {
- if (_childRefreshEquipmentId is not null)
- {
- await RefreshEquipmentChildrenAsync(_childRefreshEquipmentId);
- }
- CloseModals();
- StateHasChanged();
- }
-
- ///
- /// Reloads a single equipment node's tag/virtual-tag children in place, leaving the rest of the tree
- /// (and the user's expansion) untouched. Falls back to a full structural reload only if the node
- /// can no longer be found in the current tree. Either branch only mutates state — the caller is
- /// responsible for calling StateHasChanged() afterwards (every current caller does).
- ///
- private async Task RefreshEquipmentChildrenAsync(string equipmentId)
- {
- var node = FindEquipmentNode(equipmentId);
- if (node is null)
- {
- // Fallback: the equipment node is no longer in the current tree — reload the whole structure.
- _roots = await Svc.LoadStructureAsync();
- return;
- }
-
- var kids = await Svc.LoadEquipmentChildrenAsync(equipmentId);
- node.Children.Clear();
- node.Children.AddRange(kids);
- node.ChildCount = node.Children.Count;
- node.Loaded = true;
- node.Expanded = true;
- }
-
- /// Recursively walks the current tree for the Equipment node with the given id, or null.
- private UnsNode? FindEquipmentNode(string equipmentId)
- {
- foreach (var root in _roots)
- {
- var found = FindEquipmentNode(root, equipmentId);
- if (found is not null) { return found; }
- }
- return null;
- }
-
- private static UnsNode? FindEquipmentNode(UnsNode node, string equipmentId)
- {
- if (node.Kind == UnsNodeKind.Equipment && node.EntityId == equipmentId)
- {
- return node;
- }
-
- foreach (var child in node.Children)
- {
- var found = FindEquipmentNode(child, equipmentId);
- if (found is not null) { return found; }
- }
- return null;
- }
-
/// Reloads the tree after a successful delete and closes the confirm modal.
private async Task ReloadAndCloseAsync()
{
@@ -603,24 +364,7 @@
_lineModalAreaId = null;
_lineModalExisting = null;
_lineModalAreaOptions = Array.Empty<(string, string)>();
- _equipmentModalVisible = false;
- _equipmentModalIsNew = false;
- _equipmentModalLineId = null;
- _equipmentModalExisting = null;
- _equipmentModalLineOptions = Array.Empty<(string, string)>();
- _equipmentModalDriverOptions = Array.Empty<(string, string)>();
- _tagModalVisible = false;
- _tagModalIsNew = false;
- _tagModalEquipmentId = null;
- _tagModalExisting = null;
- _tagModalDriverOptions = Array.Empty<(string, string, string)>();
- _vtagModalVisible = false;
- _vtagModalIsNew = false;
- _vtagModalEquipmentId = null;
- _vtagModalExisting = null;
- _vtagModalScriptOptions = Array.Empty<(string, string)>();
_importModalVisible = false;
- _childRefreshEquipmentId = null;
_confirmNode = null;
_confirmError = null;
}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/EquipmentModal.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/EquipmentModal.razor
deleted file mode 100644
index 838a5e7a..00000000
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/EquipmentModal.razor
+++ /dev/null
@@ -1,252 +0,0 @@
-@* Create/edit modal for an equipment, wired straight into IUnsTreeService. The host page owns
- visibility and supplies the parent line id (create) or the loaded EquipmentEditDto (edit), plus
- the cluster-scoped UNS-line and driver lists. The EquipmentId is system-generated (decision #125)
- so it is never an editable field — only shown read-only on edit. On a successful save it raises
- OnSaved so the host can reload the tree. *@
-@using System.ComponentModel.DataAnnotations
-@using Microsoft.AspNetCore.Components.Forms
-@using ZB.MOM.WW.OtOpcUa.AdminUI.Uns
-@inject IUnsTreeService Svc
-
-@if (Visible)
-{
-
-
-
-
-
-
-
-
-
Identity
- @if (!IsNew)
- {
-
-
-
-
System-generated; never operator-edited.
-
- }
-
-
-
-
-
UNS level 5 segment; lowercase letters, digits, dashes, up to 32 chars.
-
-
-
-
-
-
-
-
-
-
-
-
-
- @foreach (var (id, display) in Lines)
- {
-
- }
-
-
-
-
-
-
-
- @foreach (var (id, display) in Drivers)
- {
-
- }
-
-
-
-
-
-
-
-
Unique fleet-wide via ExternalIdReservation.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
OPC 40010 identification (optional)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- @if (!string.IsNullOrWhiteSpace(_error))
- {
-
@_error
- }
-
-
-
-
-
-
-}
-
-@code {
- /// Whether the modal is shown. The host owns this flag.
- [Parameter] public bool Visible { get; set; }
-
- /// true to create a new equipment; false to edit .
- [Parameter] public bool IsNew { get; set; }
-
- /// The parent line id used to default the UNS-line select on create.
- [Parameter] public string? UnsLineId { get; set; }
-
- /// The equipment being edited, when is false.
- [Parameter] public EquipmentEditDto? Existing { get; set; }
-
- /// The selectable UNS lines — scoped to the equipment's cluster by the host — as (Id, Display) pairs.
- [Parameter] public IReadOnlyList<(string Id, string Display)> Lines { get; set; } = Array.Empty<(string, string)>();
-
- /// The selectable 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)>();
-
- /// Raised after a successful create/save so the host can reload and close.
- [Parameter] public EventCallback OnSaved { get; set; }
-
- /// Raised when the user cancels so the host can close.
- [Parameter] public EventCallback OnCancel { get; set; }
-
- private FormModel _form = new();
- private bool _busy;
- private string? _error;
-
- protected override void OnParametersSet()
- {
- // Rebuild the working form whenever the host (re)opens the modal for a fresh target.
- if (IsNew)
- {
- _form = new FormModel { UnsLineId = UnsLineId ?? "" };
- }
- else if (Existing is not null)
- {
- _form = new FormModel
- {
- Name = Existing.Name,
- MachineCode = Existing.MachineCode,
- UnsLineId = Existing.UnsLineId,
- DriverInstanceId = Existing.DriverInstanceId,
- ZTag = Existing.ZTag,
- SAPID = Existing.SAPID,
- Manufacturer = Existing.Manufacturer,
- Model = Existing.Model,
- SerialNumber = Existing.SerialNumber,
- HardwareRevision = Existing.HardwareRevision,
- SoftwareRevision = Existing.SoftwareRevision,
- YearOfConstruction = Existing.YearOfConstruction,
- AssetLocation = Existing.AssetLocation,
- ManufacturerUri = Existing.ManufacturerUri,
- DeviceManualUri = Existing.DeviceManualUri,
- Enabled = Existing.Enabled,
- };
- }
- _error = null;
- }
-
- private async Task SaveAsync()
- {
- _busy = true;
- _error = null;
- try
- {
- var input = new EquipmentInput(
- _form.Name,
- _form.MachineCode,
- _form.UnsLineId,
- _form.DriverInstanceId,
- _form.ZTag,
- _form.SAPID,
- _form.Manufacturer,
- _form.Model,
- _form.SerialNumber,
- _form.HardwareRevision,
- _form.SoftwareRevision,
- _form.YearOfConstruction,
- _form.AssetLocation,
- _form.ManufacturerUri,
- _form.DeviceManualUri,
- _form.Enabled);
-
- var result = IsNew
- ? await Svc.CreateEquipmentAsync(input)
- : await Svc.UpdateEquipmentAsync(Existing!.EquipmentId, input, Existing.RowVersion);
-
- if (result.Ok)
- {
- await OnSaved.InvokeAsync();
- }
- else
- {
- _error = result.Error;
- }
- }
- finally
- {
- _busy = false;
- }
- }
-
- private Task CancelAsync() => OnCancel.InvokeAsync();
-
- private sealed class FormModel
- {
- [Required, RegularExpression("^[a-z0-9-]{1,32}$", ErrorMessage = "Lowercase letters, digits, dashes only; max 32 chars.")]
- public string Name { get; set; } = "";
- [Required] public string MachineCode { get; set; } = "";
- [Required] public string UnsLineId { get; set; } = "";
- public string? DriverInstanceId { get; set; }
- public string? ZTag { get; set; }
- public string? SAPID { get; set; }
- public string? Manufacturer { get; set; }
- public string? Model { get; set; }
- public string? SerialNumber { get; set; }
- public string? HardwareRevision { get; set; }
- public string? SoftwareRevision { get; set; }
- public short? YearOfConstruction { get; set; }
- public string? AssetLocation { get; set; }
- public string? ManufacturerUri { get; set; }
- public string? DeviceManualUri { get; set; }
- public bool Enabled { get; set; } = true;
- }
-}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/UnsTree.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/UnsTree.razor
index 4b872e2e..c65b30cd 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/UnsTree.razor
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/UnsTree.razor
@@ -13,13 +13,10 @@
/// The top-level UNS nodes to render (typically the enterprise roots).
[Parameter, EditorRequired] public IReadOnlyList Roots { get; set; } = default!;
- /// Raised for the primary "add child" action of a node (e.g. "+ Area" on a cluster, "+ Tag" on equipment).
+ /// Raised for the primary "add child" action of a structural node (e.g. "+ Area" on a cluster, "+ Equipment" on a line).
[Parameter] public EventCallback OnAddChild { get; set; }
- /// Raised for the equipment-only "+ Virtual tag" action, kept distinct from OnAddChild ("+ Tag").
- [Parameter] public EventCallback OnAddVirtualTag { get; set; }
-
- /// Raised when the user edits a node (Area/Line/Equipment/Tag/VirtualTag).
+ /// Raised when the user edits a node (Area/Line).
[Parameter] public EventCallback OnEdit { get; set; }
/// Raised when the user deletes a node (Area/Line/Equipment/Tag/VirtualTag).
@@ -117,20 +114,7 @@
break;
case UnsNodeKind.Equipment:
-
-
-
-
- break;
-
- case UnsNodeKind.Tag:
- case UnsNodeKind.VirtualTag:
-
+ Open
break;
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsNode.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsNode.cs
index 80d87bbe..3265202d 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsNode.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Uns/UnsNode.cs
@@ -241,7 +241,7 @@ public static class UnsTreeAssembly
ClusterId = clusterId,
EntityId = equipment.EquipmentId,
ChildCount = childCount,
- HasLazyChildren = childCount > 0,
+ HasLazyChildren = false,
};
}
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeAssemblyTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeAssemblyTests.cs
index 05d70e02..cce549d2 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeAssemblyTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeAssemblyTests.cs
@@ -68,7 +68,7 @@ public sealed class UnsTreeAssemblyTests
}
[Fact]
- public void Build_sets_equipment_child_count_and_lazy_flag()
+ public void Build_sets_equipment_child_count_and_leaf_flag()
{
var clusters = new[] { new ClusterRow("c1", "zb", "SiteA", "Alpha") };
var areas = new[] { new AreaRow("a1", "c1", "AreaOne") };
@@ -82,9 +82,12 @@ public sealed class UnsTreeAssemblyTests
var tree = UnsTreeAssembly.Build(clusters, areas, lines, equipment);
var line = tree.Single().Children.Single().Children.Single().Children.Single();
+ // Equipment is a tree leaf that links to its own detail page, so it never carries an
+ // expander — HasLazyChildren is always false regardless of its tag/virtual-tag count.
+ // The ChildCount badge still reflects tags + virtual tags.
var withChildren = line.Children.Single(e => e.Key == "eq:e1");
withChildren.ChildCount.ShouldBe(3);
- withChildren.HasLazyChildren.ShouldBeTrue();
+ withChildren.HasLazyChildren.ShouldBeFalse();
var empty = line.Children.Single(e => e.Key == "eq:e2");
empty.ChildCount.ShouldBe(0);
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceStructureTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceStructureTests.cs
index e4c19c21..195b213f 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceStructureTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceStructureTests.cs
@@ -54,8 +54,8 @@ public sealed class UnsTreeServiceStructureTests
equipment.ClusterId.ShouldBe(UnsTreeTestDb.PopulatedClusterId);
}
- /// The seeded equipment node's badge count equals tags + virtual tags and it is
- /// flagged as lazily expandable.
+ /// The seeded equipment node's badge count equals tags + virtual tags. Equipment is a
+ /// tree leaf (no expander), so HasLazyChildren is always false.
[Fact]
public async Task LoadStructure_counts_tags_and_vtags_per_equipment()
{
@@ -72,7 +72,7 @@ public sealed class UnsTreeServiceStructureTests
// Seed: 2 driver tags + 1 virtual tag (the orphan tag has no equipment and is excluded).
equipment.ChildCount.ShouldBe(3);
- equipment.HasLazyChildren.ShouldBeTrue();
+ equipment.HasLazyChildren.ShouldBeFalse();
}
/// An empty cluster (no areas) is still rendered as a Cluster node with no children.