fix(code-review): resolve OpcUaServer-001 — UNS Area/Line rename refreshes folder DisplayName
A rename-only deploy produced an IsEmpty plan that short-circuited before MaterialiseHierarchy, leaving the OPC UA folder DisplayName stale. AddressSpacePlanner now diffs UnsAreas/UnsLines by stable id into a RenamedFolders set (counted in IsEmpty); the applier refreshes the folder in place via a new UpdateFolderDisplayName on ISurgicalAddressSpaceSink (forwarded through DeferredAddressSpaceSink so it is NOT inert on driver hosts; falls back to rebuild when the sink is non-surgical). DeploymentArtifact byte-parity untouched (rename rides the existing Name round-trip). No EF migration, no serialized wire/proto contract change. +13 OpcUaServer tests, Runtime rebuild test.
This commit is contained in:
@@ -1307,6 +1307,34 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update an EXISTING folder node's <see cref="FolderState.DisplayName"/> in place and notify
|
||||
/// subscribers, WITHOUT a rebuild — the in-place counterpart of <see cref="EnsureFolder"/> for a
|
||||
/// UNS Area / Line rename (OpcUaServer-001). <see cref="EnsureFolder"/> early-returns for an
|
||||
/// already-present folder id and never touches an existing folder's display name, so a
|
||||
/// rename-only deploy would otherwise be invisible until a full <see cref="RebuildAddressSpace"/>
|
||||
/// cleared <c>_folders</c>. The NodeId + BrowseName are unchanged (a rename only touches the
|
||||
/// friendly display name, not the logical id, so browse-path resolution + ACLs are unaffected).
|
||||
/// <c>ClearChangeMasks</c> is called so subscribed clients see the new DisplayName immediately,
|
||||
/// mirroring the <see cref="UpdateTagAttributes"/> surgical path. Returns false when the folder id
|
||||
/// is unknown (caller falls back to a full rebuild).
|
||||
/// </summary>
|
||||
/// <param name="folderNodeId">The node identifier of the folder to update in place.</param>
|
||||
/// <param name="displayName">The new display name to apply.</param>
|
||||
/// <returns>True when the in-place update was applied; false when the folder id is unknown.</returns>
|
||||
public bool UpdateFolderDisplayName(string folderNodeId, string displayName)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(folderNodeId);
|
||||
ArgumentException.ThrowIfNullOrEmpty(displayName);
|
||||
lock (Lock)
|
||||
{
|
||||
if (!_folders.TryGetValue(folderNodeId, out var folder)) return false;
|
||||
folder.DisplayName = displayName;
|
||||
folder.ClearChangeMasks(SystemContext, includeChildren: false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure a Variable node exists at <paramref name="variableNodeId"/> parented under
|
||||
/// <paramref name="parentFolderNodeId"/> (or root when null). Initial value=null, quality=Bad,
|
||||
|
||||
Reference in New Issue
Block a user