feat(dcl+ui): rename BrowseOpcUaNode -> ConnectionName-keyed; implement site handler + dialog failure mapping

- BrowseOpcUaNodeCommand: int DataConnectionId -> string ConnectionName
  (site DataConnectionManagerActor indexes children by name; CentralUI
  already has the connection name in scope via the dropdown — no extra
  plumbing across the trust boundary).
- IOpcUaBrowseService / OpcUaBrowseService: parameter renamed accordingly.
- OpcUaBrowserDialog: collapse the duplicate ConnectionName parameters
  (display label and routing key are the same string).
- Task 10: DataConnectionManagerActor forwards BrowseOpcUaNodeCommand to
  its child by name (owns ConnectionNotFound); DataConnectionActor adds
  the receive across all three lifecycle states (Connecting / Connected
  / Reconnecting) and maps adapter outcomes to BrowseFailureKind
  (NotBrowsable / ConnectionNotConnected / Timeout / ServerError).
- Task 17: SetFailure in OpcUaBrowserDialog implements the full
  BrowseFailureKind switch with friendly UI messages.
- Tests: DataConnectionManagerBrowseHandlerTests covers ConnectionNotFound,
  NotBrowsable, success, and ConnectionNotConnectedException paths.
This commit is contained in:
Joseph Doherty
2026-05-28 12:09:43 -04:00
parent 6999aedc60
commit d285174597
7 changed files with 313 additions and 13 deletions
@@ -2,6 +2,7 @@ using Akka.Actor;
using Akka.Event;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.DataConnection;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
using ZB.MOM.WW.ScadaBridge.SiteEventLogging;
@@ -45,6 +46,7 @@ public class DataConnectionManagerActor : ReceiveActor
Receive<WriteTagRequest>(HandleRouteWrite);
Receive<RemoveConnectionCommand>(HandleRemoveConnection);
Receive<GetAllHealthReports>(HandleGetAllHealthReports);
Receive<BrowseOpcUaNodeCommand>(HandleBrowse);
}
private void HandleCreateConnection(CreateConnectionCommand command)
@@ -111,6 +113,33 @@ public class DataConnectionManagerActor : ReceiveActor
}
}
/// <summary>
/// Routes a <see cref="BrowseOpcUaNodeCommand"/> from the central UI's OPC UA
/// Tag Browser to the child <see cref="DataConnectionActor"/> that owns the
/// named connection. The manager is the only actor that knows whether a
/// connection exists at this site — so it owns the
/// <see cref="BrowseFailureKind.ConnectionNotFound"/> failure. Everything
/// else (capability check, session state, server errors) lives inside the
/// child where the adapter is held.
/// </summary>
private void HandleBrowse(BrowseOpcUaNodeCommand command)
{
if (_connectionActors.TryGetValue(command.ConnectionName, out var actor))
{
actor.Forward(command);
}
else
{
_log.Warning("No connection actor for {0} during browse", command.ConnectionName);
Sender.Tell(new BrowseOpcUaNodeResult(
Array.Empty<BrowseNode>(),
Truncated: false,
new BrowseFailure(
BrowseFailureKind.ConnectionNotFound,
$"No data connection named '{command.ConnectionName}' at this site.")));
}
}
private void HandleRemoveConnection(RemoveConnectionCommand command)
{
if (_connectionActors.TryGetValue(command.ConnectionName, out var actor))