@page "/design/connections/create" @page "/design/connections/{Id:int}/edit" @page "/design/data-connections/create" @page "/design/data-connections/{Id:int}/edit" @using ZB.MOM.WW.ScadaBridge.Security @using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites @using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories @using ZB.MOM.WW.ScadaBridge.Commons.Types.DataConnections @using ZB.MOM.WW.ScadaBridge.Commons.Types.Flattening @using ZB.MOM.WW.ScadaBridge.Commons.Serialization @using ZB.MOM.WW.ScadaBridge.Commons.Validators @using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Forms @attribute [Authorize(Policy = AuthorizationPolicies.RequireDesign)] @inject ISiteRepository SiteRepository @inject NavigationManager NavigationManager

@(Id.HasValue ? "Edit Data Connection" : "Add Data Connection")

@if (_loading) { } else {
@if (_siteLocked) {
Site is locked after creation.
} else { }
@if (_protocolLocked) {
Protocol is locked after creation.
} else { }
@if (Id.HasValue && _protocol == "OpcUa") {
Manage certificates
View, trust, and remove OPC UA server certificates in the site's node-wide trusted-peer store.
}
Primary endpoint
@if (_protocol == "MxGateway") { } else { }
Backup endpoint @if (!_showBackup) { Optional }
@if (!_showBackup) {
} else { @if (_protocol == "MxGateway") { } else { }
Retries before failing over to backup endpoint.
} @if (_formError != null) {
@_formError
}
}
@code { [Parameter] public int? Id { get; set; } [SupplyParameterFromQuery] public int? SiteId { get; set; } private bool _loading = true; private DataConnection? _editingConnection; private List _sites = new(); private int _formSiteId; private string _siteName = string.Empty; private bool _siteLocked; private string _formName = string.Empty; private string _protocol = "OpcUa"; private bool _protocolLocked; private OpcUaEndpointConfig _primaryConfig = new(); private OpcUaEndpointConfig _backupConfig = new(); private MxGatewayEndpointConfig _primaryMx = new(); private MxGatewayEndpointConfig _backupMx = new(); private bool _primaryIsLegacy; private bool _backupIsLegacy; private bool _showBackup; private int _formFailoverRetryCount = 3; private ValidationResult? _primaryErrors; private ValidationResult? _backupErrors; private string? _formError; // The machine-readable site identifier (used in Akka addresses) for the currently // selected site — resolved from _formSiteId (the numeric primary key) so the // endpoint editor's Verify probe can target the owning site. Blank until a site is // chosen, which disables verification in the editor. private string _formSiteIdentifier => _sites.FirstOrDefault(s => s.Id == _formSiteId)?.SiteIdentifier ?? string.Empty; protected override async Task OnInitializedAsync() { try { _sites = (await SiteRepository.GetAllSitesAsync()).ToList(); if (Id.HasValue) { _editingConnection = await SiteRepository.GetDataConnectionByIdAsync(Id.Value); if (_editingConnection != null) { _formSiteId = _editingConnection.SiteId; _siteName = _sites.FirstOrDefault(s => s.Id == _formSiteId)?.Name ?? $"Site {_formSiteId}"; _siteLocked = true; _formName = _editingConnection.Name; _protocol = string.IsNullOrWhiteSpace(_editingConnection.Protocol) ? "OpcUa" : _editingConnection.Protocol; _protocolLocked = true; LoadConfig(_editingConnection); } } else if (SiteId.HasValue) { var site = _sites.FirstOrDefault(s => s.Id == SiteId.Value); if (site != null) { _formSiteId = site.Id; _siteName = site.Name; _siteLocked = true; } } } catch (Exception ex) { _formError = $"Failed to load: {ex.Message}"; } finally { _loading = false; } } private void LoadConfig(DataConnection conn) { if (_protocol == "MxGateway") { _primaryMx = MxGatewayEndpointConfigSerializer.Deserialize(conn.PrimaryConfiguration); if (!string.IsNullOrWhiteSpace(conn.BackupConfiguration)) { _backupMx = MxGatewayEndpointConfigSerializer.Deserialize(conn.BackupConfiguration); _showBackup = true; _formFailoverRetryCount = conn.FailoverRetryCount; } } else { (_primaryConfig, _primaryIsLegacy) = OpcUaEndpointConfigSerializer.Deserialize(conn.PrimaryConfiguration); if (!string.IsNullOrWhiteSpace(conn.BackupConfiguration)) { (_backupConfig, _backupIsLegacy) = OpcUaEndpointConfigSerializer.Deserialize(conn.BackupConfiguration); _showBackup = true; _formFailoverRetryCount = conn.FailoverRetryCount; } } } private async Task SaveConnection() { _formError = null; if (_formSiteId == 0) { _formError = "Site is required."; return; } if (string.IsNullOrWhiteSpace(_formName)) { _formError = "Name is required."; return; } string primaryJson; string? backupJson; if (_protocol == "MxGateway") { _primaryErrors = MxGatewayEndpointConfigValidator.Validate(_primaryMx, "Primary."); _backupErrors = _showBackup ? MxGatewayEndpointConfigValidator.Validate(_backupMx, "Backup.") : null; if (!_primaryErrors.IsValid || (_backupErrors is { IsValid: false })) { _formError = "Fix the errors below before saving."; return; } primaryJson = MxGatewayEndpointConfigSerializer.Serialize(_primaryMx); backupJson = _showBackup ? MxGatewayEndpointConfigSerializer.Serialize(_backupMx) : null; } else { _primaryErrors = OpcUaEndpointConfigValidator.Validate(_primaryConfig, "Primary."); _backupErrors = _showBackup ? OpcUaEndpointConfigValidator.Validate(_backupConfig, "Backup.") : null; if (!_primaryErrors.IsValid || (_backupErrors is { IsValid: false })) { _formError = "Fix the errors below before saving."; return; } primaryJson = OpcUaEndpointConfigSerializer.Serialize(_primaryConfig); backupJson = _showBackup ? OpcUaEndpointConfigSerializer.Serialize(_backupConfig) : null; } try { if (_editingConnection != null) { _editingConnection.Name = _formName.Trim(); _editingConnection.Protocol = _protocol; _editingConnection.PrimaryConfiguration = primaryJson; _editingConnection.BackupConfiguration = backupJson; _editingConnection.FailoverRetryCount = _showBackup ? _formFailoverRetryCount : 3; await SiteRepository.UpdateDataConnectionAsync(_editingConnection); } else { var conn = new DataConnection(_formName.Trim(), _protocol, _formSiteId) { PrimaryConfiguration = primaryJson, BackupConfiguration = backupJson, FailoverRetryCount = _showBackup ? _formFailoverRetryCount : 3 }; await SiteRepository.AddDataConnectionAsync(conn); } await SiteRepository.SaveChangesAsync(); NavigationManager.NavigateTo("/design/connections"); } catch (Exception ex) { _formError = $"Save failed: {ex.Message}"; } } private void EnableBackup() => _showBackup = true; private void RemoveBackup() { _showBackup = false; _backupConfig = new OpcUaEndpointConfig(); _backupMx = new MxGatewayEndpointConfig(); _backupIsLegacy = false; _formFailoverRetryCount = 3; } private void GoBack() => NavigationManager.NavigateTo("/design/connections"); }