feat(centralui): add OPC UA browse button + override column to InstanceConfigure
This commit is contained in:
+120
-3
@@ -9,6 +9,7 @@
|
||||
@using ZB.MOM.WW.ScadaBridge.TemplateEngine.Flattening
|
||||
@using ZB.MOM.WW.ScadaBridge.TemplateEngine.Services
|
||||
@using ZB.MOM.WW.ScadaBridge.DeploymentManager
|
||||
@using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Dialogs
|
||||
@attribute [Authorize(Policy = AuthorizationPolicies.RequireDeployment)]
|
||||
@inject ITemplateEngineRepository TemplateEngineRepository
|
||||
@inject ISiteRepository SiteRepository
|
||||
@@ -108,17 +109,22 @@
|
||||
<th>Attribute</th>
|
||||
<th>Tag Path</th>
|
||||
<th style="width: 280px;">Connection</th>
|
||||
<th>Override</th>
|
||||
<th style="width: 110px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var attr in _bindingDataSourceAttrs)
|
||||
{
|
||||
var connId = GetBindingConnectionId(attr.Name);
|
||||
var canBrowse = connId > 0;
|
||||
var isOpcUa = IsOpcUa(connId);
|
||||
<tr>
|
||||
<td class="small">@attr.Name</td>
|
||||
<td class="small text-muted font-monospace">@attr.DataSourceReference</td>
|
||||
<td>
|
||||
<select class="form-select form-select-sm"
|
||||
value="@GetBindingConnectionId(attr.Name)"
|
||||
value="@connId"
|
||||
@onchange="(e) => OnBindingChanged(attr.Name, e)">
|
||||
<option value="0">— none —</option>
|
||||
@foreach (var c in _siteConnections)
|
||||
@@ -127,6 +133,23 @@
|
||||
}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control form-control-sm"
|
||||
value="@GetOverrideForAttr(attr.Name)"
|
||||
@onchange="(e) => OnOverrideForAttrChanged(attr.Name, e)"
|
||||
placeholder="@(attr.DataSourceReference ?? "(no default)")" />
|
||||
</td>
|
||||
<td>
|
||||
@if (isOpcUa)
|
||||
{
|
||||
<button class="btn btn-sm btn-outline-primary"
|
||||
disabled="@(!canBrowse)"
|
||||
title="@(canBrowse ? "Browse OPC UA address space" : "Pick a connection first")"
|
||||
@onclick="() => OpenBrowser(attr.Name)">
|
||||
Browse…
|
||||
</button>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
@@ -331,6 +354,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* OPC UA Tag Browser dialog (Task 18) — rendered once; OpenBrowser
|
||||
tracks which binding row's override input receives the picked node id. *@
|
||||
<OpcUaBrowserDialog @ref="_browserRef"
|
||||
SiteId="@_browserSiteIdentifier"
|
||||
ConnectionName="@_browserConnectionName"
|
||||
InitialNodeId="@_browserInitial"
|
||||
OnSelected="OnBrowserSelected" />
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -350,8 +381,24 @@
|
||||
private List<TemplateAttribute> _bindingDataSourceAttrs = new();
|
||||
private List<DataConnection> _siteConnections = new();
|
||||
private Dictionary<string, int> _bindingSelections = new();
|
||||
/// <summary>
|
||||
/// Per-attribute <c>DataSourceReferenceOverride</c> values (Task 18). Mirrors
|
||||
/// <see cref="_bindingSelections"/> by attribute name. Loaded from the
|
||||
/// existing <see cref="InstanceConnectionBinding"/> rows on init; round-tripped
|
||||
/// through <see cref="ConnectionBinding"/> on <c>SaveBindings</c>.
|
||||
/// </summary>
|
||||
private Dictionary<string, string?> _bindingOverrides = new();
|
||||
private int _bulkConnectionId;
|
||||
|
||||
// OPC UA tag browser (Task 18) — single dialog rendered at page bottom;
|
||||
// _browserAttrInEdit tracks which row gets the picked node id on Select.
|
||||
private OpcUaBrowserDialog? _browserRef;
|
||||
private string? _browserAttrInEdit;
|
||||
private string _browserSiteIdentifier = "";
|
||||
private string _browserConnectionName = "";
|
||||
private string? _browserInitial;
|
||||
private string _siteIdentifier = "";
|
||||
|
||||
// Overrides
|
||||
private List<TemplateAttribute> _overrideAttrs = new();
|
||||
private Dictionary<string, string?> _overrideValues = new();
|
||||
@@ -407,7 +454,11 @@
|
||||
_templateName = template?.Name ?? $"#{_instance.TemplateId}";
|
||||
|
||||
var sites = await SiteRepository.GetAllSitesAsync();
|
||||
_siteName = sites.FirstOrDefault(s => s.Id == _instance.SiteId)?.Name ?? $"#{_instance.SiteId}";
|
||||
var site = sites.FirstOrDefault(s => s.Id == _instance.SiteId);
|
||||
_siteName = site?.Name ?? $"#{_instance.SiteId}";
|
||||
// Task 18: cache the site's machine identifier — the OPC UA browse
|
||||
// dialog routes by SiteIdentifier (string), not the numeric site id.
|
||||
_siteIdentifier = site?.SiteIdentifier ?? "";
|
||||
|
||||
// Areas
|
||||
_siteAreas = (await TemplateEngineRepository.GetAreasBySiteIdAsync(_instance.SiteId)).ToList();
|
||||
@@ -420,7 +471,11 @@
|
||||
_siteConnections = (await SiteRepository.GetDataConnectionsBySiteIdAsync(_instance.SiteId)).ToList();
|
||||
var existingBindings = await TemplateEngineRepository.GetBindingsByInstanceIdAsync(Id);
|
||||
foreach (var b in existingBindings)
|
||||
{
|
||||
_bindingSelections[b.AttributeName] = b.DataConnectionId;
|
||||
if (!string.IsNullOrEmpty(b.DataSourceReferenceOverride))
|
||||
_bindingOverrides[b.AttributeName] = b.DataSourceReferenceOverride;
|
||||
}
|
||||
|
||||
// Overrides
|
||||
_overrideAttrs = attrs.Where(a => !a.IsLocked).ToList();
|
||||
@@ -474,12 +529,74 @@
|
||||
_bindingSelections[attr.Name] = _bulkConnectionId;
|
||||
}
|
||||
|
||||
// ── Task 18: per-attribute override input + OPC UA tag browser ──────────
|
||||
|
||||
private string? GetOverrideForAttr(string attrName)
|
||||
=> _bindingOverrides.GetValueOrDefault(attrName);
|
||||
|
||||
private void OnOverrideForAttrChanged(string attrName, ChangeEventArgs e)
|
||||
{
|
||||
var val = e.Value?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(val))
|
||||
_bindingOverrides.Remove(attrName);
|
||||
else
|
||||
_bindingOverrides[attrName] = val;
|
||||
}
|
||||
|
||||
/// <summary>Looks up the template default <c>DataSourceReference</c> for an attribute.</summary>
|
||||
private string? GetTemplateDefault(string attrName)
|
||||
=> _bindingDataSourceAttrs.FirstOrDefault(a => a.Name == attrName)?.DataSourceReference;
|
||||
|
||||
/// <summary>True when the row's selected data connection is OPC UA.</summary>
|
||||
private bool IsOpcUa(int connectionId)
|
||||
=> connectionId > 0
|
||||
&& string.Equals(
|
||||
_siteConnections.FirstOrDefault(c => c.Id == connectionId)?.Protocol,
|
||||
"OpcUa",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Opens the OPC UA tag browser dialog for the given attribute row. Remembers
|
||||
/// which attribute is being edited so <see cref="OnBrowserSelected"/> can
|
||||
/// write the picked node id back to the right override input.
|
||||
/// </summary>
|
||||
private async Task OpenBrowser(string attrName)
|
||||
{
|
||||
var connId = GetBindingConnectionId(attrName);
|
||||
var conn = _siteConnections.FirstOrDefault(c => c.Id == connId);
|
||||
if (conn is null) return;
|
||||
|
||||
_browserAttrInEdit = attrName;
|
||||
_browserConnectionName = conn.Name;
|
||||
_browserSiteIdentifier = _siteIdentifier;
|
||||
_browserInitial = _bindingOverrides.GetValueOrDefault(attrName)
|
||||
?? GetTemplateDefault(attrName);
|
||||
|
||||
if (_browserRef is not null)
|
||||
await _browserRef.ShowAsync();
|
||||
}
|
||||
|
||||
private void OnBrowserSelected(string nodeId)
|
||||
{
|
||||
if (_browserAttrInEdit is null) return;
|
||||
_bindingOverrides[_browserAttrInEdit] = nodeId;
|
||||
_browserAttrInEdit = null;
|
||||
}
|
||||
|
||||
private async Task SaveBindings()
|
||||
{
|
||||
_saving = true;
|
||||
try
|
||||
{
|
||||
var bindings = _bindingSelections.Select(kv => new ConnectionBinding(kv.Key, kv.Value)).ToList();
|
||||
// Task 18: include the per-attribute DataSourceReferenceOverride on
|
||||
// the wire record so it round-trips through SetConnectionBindingsAsync
|
||||
// into the InstanceConnectionBinding entity.
|
||||
var bindings = _bindingSelections
|
||||
.Select(kv => new ConnectionBinding(
|
||||
kv.Key,
|
||||
kv.Value,
|
||||
_bindingOverrides.GetValueOrDefault(kv.Key)))
|
||||
.ToList();
|
||||
var user = await GetCurrentUserAsync();
|
||||
var result = await InstanceService.SetConnectionBindingsAsync(Id, bindings, user);
|
||||
if (result.IsSuccess)
|
||||
|
||||
Reference in New Issue
Block a user